Compare commits

...

6 Commits
v043 ... v047

Author SHA1 Message Date
byuu
7b0e484c18 Update to bsnes v047 release.
The most notable feature for this release is the addition of SuperFX support. This enables an additional eight commercial games, and two unreleased betas, to run with full support. Most notably of these would be Super Mario World 2: Yoshi's Island and Starfox. Though timing is not quite perfect just yet, there should be no known issues with any titles at the time of this release. That means there should only be two official, commercially-released titles that are not compatible with bsnes at this time: Quick-move Shogi Match with Nidan Rank-holder Morita 1 and 2 (using the ST011 and ST018 co-processors, respectively.)
SuperFX support was the work of many people. GIGO was a great help by providing the source code to his SuperFX emulator (for reference; the implementation in bsnes is my own design), _Demo_ was very helpful in getting Starfox to work properly, and Jonas Quinn provided roughly a half-dozen very important bug fixes that affected nearly every SuperFX game. Without them, this release would not be possible. So please do thank them if you appreciate SuperFX support in bsnes.
Please note that SuperFX emulation is very demanding. I hate to have to repeat this, but once again: bsnes is a reference emulator. It exists to better understand the SNES hardware. It is written in such a manner as to be friendly to other developers (both emulator authors and game programmers), and the findings are meant to help improve other emulators. As far as I know, bsnes is the first emulator to fully support all SuperFX caching mechanisms (instruction cache, both pixel caches, ROM and RAM buffering caches, ...); as well as many other obscure features, such as full support for ROM / RAM access toggling between the SNES and SuperFX CPUs, and multiplier overhead timing. By emulating these, I was able to discover what additional components are needed to emulate Dirt Racer and Power Slide, two titles that no emulator has yet been able to run (they aren't very good games, you weren't missing much.) It should be possible to backport these fixes to faster emulators now.
That said, with a Core 2 Duo E8400 @ 3GHz, on average I get ~100fps in Super Mario World 2, ~95fps in Starfox and ~85fps in Doom. Compare this to ~165fps in Zelda 3, a game that does not use the SuperFX chip. My binary releases also target 32-bit x86 architecture. For those capable of building 64-bit binaries, especially Linux users, that should provide an additional ~10% speedup. Be sure to profile the application if you build it yourself.
Lastly on the SuperFX front, note that Starfox 2 is fully playable, but that most images floating around have corrupted headers. I do not attempt to repair bad headers, so these images will not work. Please either use NSRT on the Japanese version, or use Gideon Zhi's English fan translation patch, if you are having trouble running this title.
With that out the way, a few other improvements have been made to this release: xinput1_3.dll is no longer required for the Windows port (though you will need it if you want to use an Xbox 360 controller), the video drivers in ruby now allocate the smallest texture size possible for blitting video, and the code has been updated with preliminary compilation support for Mac OS X. Note that I will not be releasing binaries for this: it is primarily meant for developers and for porting my other libraries to the platform. Richard Bannister maintains a much better OS X port with full EE support and a native Apple GUI that follows their interface guidelines much better than a Qt port ever could. He has also synced the Mac port with this release. You can find a link to that in the bsnes download section.
2009-06-07 11:57:05 +00:00
byuu
f8e425ff49 Update to bsnes v046a release.
[No changelog available]
2009-05-12 02:33:49 +00:00
byuu
2a6a66f478 Update to bsnes v046 release.
Unfortunately, I was not able to include any actual Super Game Boy support in this release. I was however able to back-port all other changes since v045, as well as add a lot of new stuff. Though there are few visible changes from the last release, internally much has changed. I'm releasing this mostly as a point release whilst everything should be stable.
I've decided to support the Super Game Boy via external DLL (or SO for Linux users.) There are many reasons for this. Most notably is that the largest special chip in bsnes right now weighs in at ~30kb of code. Emulating an entire Game Boy, not including the SGB enhancements, would require an additional ~800kb of code, or nearly half the size of the entire SNES emulation core. Add to that potential issues with licensing, conflicts with the build process / namespace, a significant increase to build time, and a lack of flexibility over which Game Boy emulator to use, and it's pretty clear that this is something best left external. At least until we have a fully trimmed, fully working SGB emulator available.
The way this will work is bsnes will look for SuperGameBoy.(dll,so), and if present, it will call out to pre-defined functions. Users will need the SGB BIOS loaded, at which point they can select a Game Boy cartridge, and bsnes will use the DLL for actual emulation. Sadly I don't have a working DLL ready for this release, and even if I did, there's no sound bridge yet for the Game Boy audio.
Other than that, much of the core has been updated in an attempt to make the core more library-like. It still has a few major limitations: it requires libco (which is not portable) and nall (which is quite large), and only one instance can be instantiated as all of the base objects are pre-defined and inter-linked. Not that I can imagine any practical use for multiple simultaneous SNES emulators anyway ...
Changelog:
    - Save RAM is now automatically saved once per minute
    - Added delay to Super Scope / Justifier latching to fix X-Zone
    - Fixed an edge case in CPU<>PPU counter history
    - S-CPU can now run up to one full scanline ahead of S-PPU before syncing
    - Added interface for Super Game Boy support (no emulation yet)
    - Fixed a bug with path selection not adding trailing slash
    - All S-SMP opcodes re-written to use new pre-processor
    - Entire core encapsulated into SNES namespace
    - Core accepts files via memory only; zlib and libjma moved outside of core
    - Major Makefile restructuring: it's now possible to build with just "make" alone
    - Linux: libxtst / inputproto is no longer required for compilation
    - Lots of additional code cleanup
2009-05-10 11:01:02 +00:00
byuu
3c42e6caa0 Update to bsnes v045r09 release.
[No changelog available]
2009-04-30 20:58:39 +00:00
byuu
5f96547beb Update to bsnes v045 release.
This is a maintenance release to fix a crashing bug in S-DD1 games (Star Ocean, Street Fighter Alpha 2), and a video issue in games using the WAI instruction.
As always, my apologies for any inconvenience. SA-1 support required modification of a large amount of delicate code in the emulation core, and our limited testing team was not able to catch these in time before release.
2009-04-20 02:55:33 +00:00
byuu
44b5f1bf27 Update to bsnes v044 release.
This release adds full SA-1 support, with no known issues. All 26 games have been tested by myself and others, and a few have been beaten from start to finish. The latter include Super Mario RPG, Kirby's Dreamland 3, Kirby Super Star and Jikkyou Oshaberi Parodius.
Please understand that the SA-1 is essentially four times faster than the SNES' main CPU, so system requirements will be very high for these games. For example, on an E8400 @ 3.0GHz, I average ~160fps in ordinary games. But for SA-1 emulation, this drops to ~90fps, with the worst case being ~80fps.
The following features are emulated:
    - 5a22 CPU core (bus-cycle accurate)
    - Memory access timing
    - SA-1 -> S-CPU interrupts (IRQ + CHDMA IRQ)
    - S-CPU -> SA-1 interrupts (IRQ + Timer IRQ + DMA IRQ + NMI)
    - SIV / SNV interrupt vector selection
    - Timer unit (linear and H/V)
    - Super MMC unit (ROM + BW-RAM)
    - BS-X flash cart slot mapping
    - Normal DMA
    - Character-conversion 1 DMA (2bpp + 4bpp + 8bpp)
    - Character-conversion 2 DMA (2bpp + 4bpp + 8bpp)
    - BW-RAM virtual bitmap mode (2bpp + 4bpp)
    - Arithmetic unit (multiplication + division + cumulative sum)
    - Variable-length bit processing (fixed and auto increment)
While the following features are not currently emulated, mostly due to lack of information:
    - SA-1 bus conflict delays
    - Write protection (BW-RAM + I-RAM)
    - SA-1 CPU priority for DMA transfers
    - DMA access timing
2009-04-19 21:34:23 +00:00
396 changed files with 36439 additions and 33345 deletions

View File

@@ -1,69 +1,53 @@
include lib/nall/Makefile.string
prefix = /usr/local
include lib/nall/Makefile
include lib/nall/Makefile-qt
ui = ui_qt
################
### compiler ###
################
ifneq ($(findstring gcc,$(compiler)),) # GCC family
flags = -O3 -fomit-frame-pointer -Ilib
# note: libco *requires* -fomit-frame-pointer on i386 arch
libcoflags := $(flags) -static
c = $(compiler)
cpp = $(subst cc,++,$(compiler))
obj = o
rule = -c $< -o $@
link = -s
mkbin = -o$1
mkdef = -D$1
mkincpath = -I$1
mklib = -l$1
mklibpath = -L$1
c := $(compiler)
cpp := $(subst cc,++,$(compiler))
flags := -O3 -fomit-frame-pointer -Ilib
link :=
# profile-guided optimization:
# flags += -fprofile-generate
# link += -lgcov
# flags += -fprofile-use
else ifeq ($(compiler),cl) # Visual C++
flags = /nologo /wd4355 /wd4805 /wd4996 /Ox /GL /EHsc /Ilib
libcoflags = $(flags)
c = cl
cpp = cl
obj = obj
rule = /c $< /Fo$@
link = /link
mkbin = /Fe$1
mkdef = /D$1
mkincpath = /I$1
mklib = $1.lib
mklibpath = /L$1
else
unknown_compiler: help;
endif
# profile-guided instrumentation:
# flags += -fprofile-generate
# link += -lgcov
##########
### os ###
##########
# profile-guided optimization:
# flags += -fprofile-use
ifeq ($(platform),x) # X11
ruby = video.glx video.xv video.sdl audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao input.sdl input.x
delete = rm -f $1
else ifeq ($(platform),win) # Windows
mingw_link_flags = -mwindows
# mingw_links_flags = -mconsole
################
### platform ###
################
# enable static linking to Qt for Windows build
mingw_link_flags += -enable-stdcall-fixup -Wl,-s -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
ifeq ($(platform),x)
link += -s
ruby = video.direct3d video.wgl video.directdraw video.gdi audio.directsound input.rawinput input.directinput
delete = $(if $(findstring i586-mingw-gcc,$(compiler)),rm -f $1,del $(subst /,\,$1))
link += $(if $(findstring mingw,$(compiler)),$(mingw_link_flags))
link += $(call mklib,uuid)
link += $(call mklib,kernel32)
link += $(call mklib,user32)
link += $(call mklib,gdi32)
link += $(call mklib,shell32)
ruby := video.glx video.xv video.sdl video.qtimage
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
ruby := video.qtimage
ruby += audio.openal
ruby += input.carbon
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
link += -mwindows
# link += -mconsole
link += -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
ruby := video.direct3d video.wgl video.directdraw video.gdi video.qtimage
ruby += audio.directsound
ruby += input.rawinput input.directinput
link += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
else
unknown_platform: help;
endif
@@ -72,39 +56,39 @@ endif
### ruby ###
############
rubyflags = $(if $(findstring .sdl,$(ruby)),`sdl-config --cflags`)
link += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
rubyflags := $(call ifhas,.sdl,$(ruby),`sdl-config --cflags`)
rubyflags += $(call ifhas,.qt,$(ruby),$(qtinc))
link += $(if $(findstring video.direct3d,$(ruby)),$(call mklib,d3d9))
link += $(if $(findstring video.directdraw,$(ruby)),$(call mklib,ddraw))
link += $(if $(findstring video.glx,$(ruby)),$(call mklib,GL))
link += $(if $(findstring video.wgl,$(ruby)),$(call mklib,opengl32))
link += $(if $(findstring video.xv,$(ruby)),$(call mklib,Xv))
link += $(if $(findstring audio.alsa,$(ruby)),$(call mklib,asound))
link += $(if $(findstring audio.ao,$(ruby)),$(call mklib,ao))
link += $(if $(findstring audio.directsound,$(ruby)),$(call mklib,dsound))
link += $(if $(findstring audio.openal,$(ruby)),$(if $(call streq,$(platform),x),$(call mklib,openal),$(call mklib,openal32)))
link += $(if $(findstring audio.pulseaudio,$(ruby)),$(call mklib,pulse-simple))
link += $(if $(findstring input.directinput,$(ruby)),$(call mklib,dinput8) $(call mklib,dxguid))
link += $(if $(findstring input.rawinput,$(ruby)),$(call mklib,xinput) $(call mklib,dinput8) $(call mklib,dxguid))
link += $(call ifhas,.sdl,$(ruby),`sdl-config --libs`)
link += $(call ifhas,video.direct3d,$(ruby),-ld3d9)
link += $(call ifhas,video.directdraw,$(ruby),-lddraw)
link += $(call ifhas,video.glx,$(ruby),-lGL)
link += $(call ifhas,video.wgl,$(ruby),-lopengl32)
link += $(call ifhas,video.xv,$(ruby),-lXv)
link += $(call ifhas,audio.alsa,$(ruby),-lasound)
link += $(call ifhas,audio.ao,$(ruby),-lao)
link += $(call ifhas,audio.directsound,$(ruby),-ldsound)
link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple)
link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid)
link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
####################
### core objects ###
####################
objects = libco ruby libfilter string \
reader cart cheat \
memory smemory cpu cpucore scpu smp ssmp sdsp ppu bppu snes \
sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
objects := libco ruby libreader libfilter
objects += system cartridge cheat
objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
objects += sgb superfx sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
ifeq ($(enable_gzip),true)
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
flags += $(call mkdef,GZIP_SUPPORT)
flags += -DGZIP_SUPPORT
endif
ifeq ($(enable_jma),true)
objects += jma jcrc32 lzmadec 7zlzma iiostrm inbyte lzma winout
flags += $(call mkdef,JMA_SUPPORT)
flags += -DJMA_SUPPORT
endif
######################
@@ -114,136 +98,143 @@ endif
compile = \
$(strip \
$(if $(filter %.c,$<), \
$(c) $(flags) $1 $(rule), \
$(c) $(flags) $1 -c $< -o $@, \
$(if $(filter %.cpp,$<), \
$(cpp) $(flags) $1 $(rule) \
$(cpp) $(flags) $1 -c $< -o $@ \
) \
) \
)
%.$(obj): $<; $(call compile)
%.o: $<; $(call compile)
all: build;
include $(ui)/Makefile
objects := $(patsubst %,obj/%.$(obj),$(objects))
rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),$(call mkdef,$c))
objects := $(patsubst %,obj/%.o,$(objects))
rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
#################
### libraries ###
#################
obj/ruby.$(obj): lib/ruby/ruby.cpp lib/ruby/* lib/ruby/video/* lib/ruby/audio/* lib/ruby/input/*
obj/ruby.o: lib/ruby/ruby.cpp $(call rwildcard,lib/ruby/*)
$(call compile,$(rubydef) $(rubyflags))
obj/libco.$(obj): lib/libco/libco.c lib/libco/*
$(c) $(libcoflags) $(rule)
obj/libfilter.$(obj): lib/libfilter/libfilter.cpp lib/libfilter/*
obj/string.$(obj): lib/nall/string.cpp lib/nall/*
obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/*
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
#################
### utilities ###
#################
obj/reader.$(obj): reader/reader.cpp reader/*
obj/cart.$(obj) : cart/cart.cpp cart/*
obj/cheat.$(obj) : cheat/cheat.cpp cheat/*
obj/cartridge.o: cartridge/cartridge.cpp cartridge/*
obj/cheat.o : cheat/cheat.cpp cheat/*
##############
### memory ###
##############
obj/memory.$(obj) : memory/memory.cpp memory/*
obj/smemory.$(obj): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/mapper/*
obj/memory.o : memory/memory.cpp memory/*
obj/smemory.o: memory/smemory/smemory.cpp $(call rwildcard,memory/smemory/)
###########
### cpu ###
###########
obj/cpu.$(obj) : cpu/cpu.cpp cpu/*
obj/cpucore.$(obj): cpu/core/core.cpp cpu/core/* cpu/core/disasm/*
obj/scpu.$(obj) : cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/*
obj/cpu.o : cpu/cpu.cpp cpu/*
obj/cpucore.o: cpu/core/core.cpp $(call rwildcard,cpu/core/)
obj/scpu.o : cpu/scpu/scpu.cpp $(call rwildcard,cpu/scpu/)
###########
### smp ###
###########
obj/smp.$(obj) : smp/smp.cpp smp/*
obj/ssmp.$(obj): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ssmp/timing/*
obj/smp.o : smp/smp.cpp smp/*
obj/smpcore.o: smp/core/core.cpp $(call rwildcard,smp/core/)
obj/ssmp.o : smp/ssmp/ssmp.cpp $(call rwildcard,smp/ssmp/)
###########
### dsp ###
###########
obj/adsp.$(obj): dsp/adsp/adsp.cpp dsp/adsp/*
obj/sdsp.$(obj): dsp/sdsp/sdsp.cpp dsp/sdsp/*
obj/adsp.o: dsp/adsp/adsp.cpp dsp/adsp/*
obj/sdsp.o: dsp/sdsp/sdsp.cpp dsp/sdsp/*
###########
### ppu ###
###########
obj/ppu.$(obj) : ppu/ppu.cpp ppu/*
obj/bppu.$(obj): ppu/bppu/bppu.cpp ppu/bppu/*
obj/ppu.o : ppu/ppu.cpp ppu/*
obj/bppu.o: ppu/bppu/bppu.cpp ppu/bppu/*
############
### snes ###
############
##############
### system ###
##############
obj/snes.$(obj): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/*
obj/system.o: system/system.cpp $(call rwildcard,system/)
#####################
### special chips ###
#####################
obj/sa1.$(obj) : chip/sa1/sa1.cpp chip/sa1/* chip/sa1/bus/* chip/sa1/dma/* chip/sa1/memory/* chip/sa1/mmio/*
obj/bsx.$(obj) : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.$(obj) : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.$(obj) : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.$(obj): chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.$(obj) : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.$(obj) : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.$(obj) : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.$(obj) : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.$(obj) : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.$(obj) : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.$(obj) : chip/st010/st010.cpp chip/st010/*
obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/)
obj/superfx.o: chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.o : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.o: chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.o : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.o : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.o : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.o : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.o : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.o : chip/st010/st010.cpp chip/st010/*
############
### zlib ###
############
obj/adler32.$(obj) : reader/zlib/adler32.c reader/zlib/*
obj/compress.$(obj): reader/zlib/compress.c reader/zlib/*
obj/crc32.$(obj) : reader/zlib/crc32.c reader/zlib/*
obj/deflate.$(obj) : reader/zlib/deflate.c reader/zlib/*
obj/gzio.$(obj) : reader/zlib/gzio.c reader/zlib/*
obj/inffast.$(obj) : reader/zlib/inffast.c reader/zlib/*
obj/inflate.$(obj) : reader/zlib/inflate.c reader/zlib/*
obj/inftrees.$(obj): reader/zlib/inftrees.c reader/zlib/*
obj/ioapi.$(obj) : reader/zlib/ioapi.c reader/zlib/*
obj/trees.$(obj) : reader/zlib/trees.c reader/zlib/*
obj/unzip.$(obj) : reader/zlib/unzip.c reader/zlib/*
obj/zip.$(obj) : reader/zlib/zip.c reader/zlib/*
obj/zutil.$(obj) : reader/zlib/zutil.c reader/zlib/*
obj/adler32.o : lib/zlib/adler32.c lib/zlib/*
obj/compress.o: lib/zlib/compress.c lib/zlib/*
obj/crc32.o : lib/zlib/crc32.c lib/zlib/*
obj/deflate.o : lib/zlib/deflate.c lib/zlib/*
obj/gzio.o : lib/zlib/gzio.c lib/zlib/*
obj/inffast.o : lib/zlib/inffast.c lib/zlib/*
obj/inflate.o : lib/zlib/inflate.c lib/zlib/*
obj/inftrees.o: lib/zlib/inftrees.c lib/zlib/*
obj/ioapi.o : lib/zlib/ioapi.c lib/zlib/*
obj/trees.o : lib/zlib/trees.c lib/zlib/*
obj/unzip.o : lib/zlib/unzip.c lib/zlib/*
obj/zip.o : lib/zlib/zip.c lib/zlib/*
obj/zutil.o : lib/zlib/zutil.c lib/zlib/*
###########
### jma ###
###########
##############
### libjma ###
##############
obj/jma.$(obj) : reader/jma/jma.cpp reader/jma/*
obj/jcrc32.$(obj) : reader/jma/jcrc32.cpp reader/jma/*
obj/lzmadec.$(obj): reader/jma/lzmadec.cpp reader/jma/*
obj/7zlzma.$(obj) : reader/jma/7zlzma.cpp reader/jma/*
obj/iiostrm.$(obj): reader/jma/iiostrm.cpp reader/jma/*
obj/inbyte.$(obj) : reader/jma/inbyte.cpp reader/jma/*
obj/lzma.$(obj) : reader/jma/lzma.cpp reader/jma/*
obj/winout.$(obj) : reader/jma/winout.cpp reader/jma/*
obj/jma.o : lib/libjma/jma.cpp lib/libjma/*
obj/jcrc32.o : lib/libjma/jcrc32.cpp lib/libjma/*
obj/lzmadec.o: lib/libjma/lzmadec.cpp lib/libjma/*
obj/7zlzma.o : lib/libjma/7zlzma.cpp lib/libjma/*
obj/iiostrm.o: lib/libjma/iiostrm.cpp lib/libjma/*
obj/inbyte.o : lib/libjma/inbyte.cpp lib/libjma/*
obj/lzma.o : lib/libjma/lzma.cpp lib/libjma/*
obj/winout.o : lib/libjma/winout.cpp lib/libjma/*
###############
### targets ###
###############
build: ui_build $(objects)
$(strip $(cpp) $(call mkbin,../bsnes) $(objects) $(link))
ifeq ($(platform),osx)
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
else
$(strip $(cpp) -o ../bsnes $(objects) $(link))
endif
install:
install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes
@@ -251,7 +242,7 @@ install:
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
clean: ui_clean
-@$(call delete,obj/*.$(obj))
-@$(call delete,obj/*.o)
-@$(call delete,*.res)
-@$(call delete,*.pgd)
-@$(call delete,*.pgc)
@@ -270,7 +261,6 @@ help:
@echo " gcc - GCC compiler"
@echo " mingw32-gcc - MinGW compiler"
@echo " i586-mingw32-gcc - MinGW cross compiler"
@echo " cl - Visual C++"
@echo ""
@echo "Available options:"
@echo " enable_gzip=[true|false] - Enable ZIP / GZ support (default=false)"

View File

@@ -1,4 +1,4 @@
#define BSNES_VERSION "0.043"
#define BSNES_VERSION "0.047"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#define BUSCORE sBus
@@ -9,12 +9,7 @@
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
#define USE_STATE_MACHINE
//FAST_FRAMESKIP disables calculation of RTO during frameskip
//frameskip offers near-zero speedup if RTO is calculated
//accuracy is not affected by this define when frameskipping is off
#define FAST_FRAMESKIP
#define DSP_STATE_MACHINE
//game genie + pro action replay code support (~2% speed hit)
#define CHEAT_SYSTEM
@@ -25,8 +20,9 @@
#include <nall/array.hpp>
#include <nall/bit.hpp>
#include <nall/detect.hpp>
#include <nall/dl.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/new.hpp>
#include <nall/platform.hpp>

View File

@@ -1,234 +0,0 @@
#include <../base.hpp>
#include <../chip/chip.hpp>
#include <../reader/reader.hpp>
#define CART_CPP
#include <nall/crc32.hpp>
#include <nall/ups.hpp>
#include "cart.hpp"
#include "cart_file.cpp"
#include "cart_header.cpp"
#include "cart_loader.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bscram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
};
Cartridge cartridge;
void Cartridge::load_begin(Mode cartridge_mode) {
cart.rom = cart.ram = cart.rtc = 0;
bs.ram = 0;
stA.rom = stA.ram = 0;
stB.rom = stB.ram = 0;
cart.rom_size = cart.ram_size = cart.rtc_size = 0;
bs.ram_size = 0;
stA.rom_size = stA.ram_size = 0;
stB.rom_size = stB.ram_size = 0;
set(loaded, false);
set(bsx_flash_loaded, false);
set(patched, false);
set(mode, cartridge_mode);
}
void Cartridge::load_end() {
memory::cartrom.map(cart.rom, cart.rom_size);
memory::cartram.map(cart.ram, cart.ram_size);
memory::cartrtc.map(cart.rtc, cart.rtc_size);
memory::bscram.map(bs.ram, bs.ram_size);
memory::stArom.map(stA.rom, stA.rom_size);
memory::stAram.map(stA.ram, stA.ram_size);
memory::stBrom.map(stB.rom, stB.rom_size);
memory::stBram.map(stB.ram, stB.ram_size);
memory::cartrom.write_protect(true);
memory::cartram.write_protect(false);
memory::bscram.write_protect(true);
memory::stArom.write_protect(true);
memory::stAram.write_protect(false);
memory::stBrom.write_protect(true);
memory::stBram.write_protect(false);
string cheat_file = get_filename(cart.filename, "cht", snes.config.path.cheat);
if(file::exists(cheat_file)) {
cheat.clear();
cheat.load(cheat_file);
}
bus.load_cart();
set(loaded, true);
}
void Cartridge::unload() {
if(loaded() == false) return;
bus.unload_cart();
switch(mode()) {
case ModeNormal: unload_normal(); break;
case ModeBsxSlotted: unload_bsx_slotted(); break;
case ModeBsx: unload_bsx(); break;
case ModeSufamiTurbo: unload_sufami_turbo(); break;
}
if(cart.rom) { delete[] cart.rom; cart.rom = 0; }
if(cart.ram) { delete[] cart.ram; cart.ram = 0; }
if(cart.rtc) { delete[] cart.rtc; cart.rtc = 0; }
if(bs.ram) { delete[] bs.ram; bs.ram = 0; }
if(stA.rom) { delete[] stA.rom; stA.rom = 0; }
if(stA.ram) { delete[] stA.ram; stA.ram = 0; }
if(stB.rom) { delete[] stB.rom; stB.rom = 0; }
if(stB.ram) { delete[] stB.ram; stB.ram = 0; }
string cheat_file = get_filename(cart.filename, "cht", snes.config.path.cheat);
if(cheat.count() > 0 || file::exists(cheat_file)) {
cheat.save(cheat_file);
cheat.clear();
}
set(loaded, false);
}
Cartridge::Cartridge() {
set(loaded, false);
}
Cartridge::~Cartridge() {
if(loaded() == true) unload();
}
void Cartridge::set_cartinfo(const Cartridge::cartinfo_t &source) {
set(region, source.region);
set(mapper, source.mapper);
set(dsp1_mapper, source.dsp1_mapper);
set(has_bsx_slot, source.bsx_slot);
set(has_superfx, source.superfx);
set(has_sa1, source.sa1);
set(has_srtc, source.srtc);
set(has_sdd1, source.sdd1);
set(has_spc7110, source.spc7110);
set(has_spc7110rtc, source.spc7110rtc);
set(has_cx4, source.cx4);
set(has_dsp1, source.dsp1);
set(has_dsp2, source.dsp2);
set(has_dsp3, source.dsp3);
set(has_dsp4, source.dsp4);
set(has_obc1, source.obc1);
set(has_st010, source.st010);
set(has_st011, source.st011);
set(has_st018, source.st018);
}
//==========
//cartinfo_t
//==========
void Cartridge::cartinfo_t::reset() {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = 0;
ram_size = 0;
bsx_slot = false;
superfx = false;
sa1 = false;
srtc = false;
sdd1 = false;
spc7110 = false;
spc7110rtc = false;
cx4 = false;
dsp1 = false;
dsp2 = false;
dsp3 = false;
dsp4 = false;
obc1 = false;
st010 = false;
st011 = false;
st018 = false;
}
Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
//=======
//utility
//=======
//ensure file path is absolute (eg resolve relative paths)
string Cartridge::filepath(const char *filename, const char *pathname) {
//if no pathname, return filename as-is
string file(filename);
file.replace("\\", "/");
string path = (!pathname || !*pathname) ? (const char*)snes.config.path.current : pathname;
//ensure path ends with trailing '/'
path.replace("\\", "/");
if(!strend(path, "/")) path.append("/");
//replace relative path with absolute path
if(strbegin(path, "./")) {
ltrim(path, "./");
path = string() << snes.config.path.base << path;
}
//remove folder part of filename
lstring part;
part.split("/", file);
return path << part[part.size() - 1];
}
//remove directory information and file extension ("/foo/bar.ext" -> "bar")
string Cartridge::basename(const char *filename) {
string name(filename);
//remove extension
for(signed i = strlen(name) - 1; i >= 0; i--) {
if(name[i] == '.') {
name[i] = 0;
break;
}
}
//remove directory information
for(signed i = strlen(name) - 1; i >= 0; i--) {
if(name[i] == '/' || name[i] == '\\') {
i++;
char *output = name();
while(true) {
*output++ = name[i];
if(!name[i]) break;
i++;
}
break;
}
}
return name;
}
//remove filename and return path only ("/foo/bar.ext" -> "/foo/bar/")
string Cartridge::basepath(const char *filename) {
string path(filename);
path.replace("\\", "/");
//remove filename
for(signed i = strlen(path) - 1; i >= 0; i--) {
if(path[i] == '/') {
path[i] = 0;
break;
}
}
if(!strend(path, "/")) path.append("/");
return path;
}

View File

@@ -1,179 +0,0 @@
class Cartridge : public property {
public:
enum Mode {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
ModeSufamiTurbo,
};
enum Type {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeUnknown,
};
enum Region {
NTSC,
PAL,
};
enum MemoryMapper {
LoROM,
HiROM,
ExLoROM,
ExHiROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
//properties can be read via operator(), eg "if(cartridge.loaded() == true)";
//warning: if loaded() == false, no other property is considered valid!
property_t<bool> loaded; //is a base cartridge inserted?
property_t<bool> bsx_flash_loaded; //is a BS-X flash cart connected?
property_t<bool> patched; //has a UPS patch been applied?
property_t<string> name; //display name (filename sans path and extension)
property_t<Mode> mode;
property_t<Region> region;
property_t<MemoryMapper> mapper;
property_t<DSP1MemoryMapper> dsp1_mapper;
property_t<bool> has_bsx_slot;
property_t<bool> has_superfx;
property_t<bool> has_sa1;
property_t<bool> has_srtc;
property_t<bool> has_sdd1;
property_t<bool> has_spc7110, has_spc7110rtc;
property_t<bool> has_cx4;
property_t<bool> has_dsp1, has_dsp2, has_dsp3, has_dsp4;
property_t<bool> has_obc1;
property_t<bool> has_st010, has_st011, has_st018;
//main interface
bool load_normal (const char *base);
bool load_bsx_slotted (const char *base, const char *slot = "");
bool load_bsx (const char *base, const char *slot = "");
bool load_sufami_turbo(const char *base, const char *slotA = "", const char *slotB = "");
void unload();
//utility functions
static string filepath(const char *filename, const char *pathname); //"./bar.ext" -> "/foo/bar.ext"
static string basename(const char *filename); //"/foo/bar.ext" -> "bar"
static string basepath(const char *filename); //"/foo/bar.ext" -> "/foo/bar/"
//this function will load 'filename', decompress it if needed, and determine what type of
//image file 'filename' refers to (eg normal cart, BS-X flash cart, Sufami Turbo cart, etc.)
//warning: this operation is very expensive, use sparingly!
Type detect_image_type(const char *filename) const;
Cartridge();
~Cartridge();
private:
void load_begin(Mode);
void load_end();
void unload_normal();
void unload_bsx_slotted();
void unload_bsx();
void unload_sufami_turbo();
struct cartinfo_t {
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
unsigned rom_size, ram_size;
bool bsx_slot;
bool superfx;
bool sa1;
bool srtc;
bool sdd1;
bool spc7110, spc7110rtc;
bool cx4;
bool dsp1, dsp2, dsp3, dsp4;
bool obc1;
bool st010, st011, st018;
void reset();
cartinfo_t();
};
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
RomSize = 0x17,
RamSize = 0x18,
CartRegion = 0x19,
Company = 0x1a,
Version = 0x1b,
Complement = 0x1c, //inverse checksum
Checksum = 0x1e,
ResetVector = 0x3c,
};
void read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const;
unsigned find_header(const uint8_t *data, unsigned size) const;
unsigned score_header(const uint8_t *data, unsigned size, unsigned addr) const;
void set_cartinfo(const cartinfo_t&);
bool load_image(const char *filename, uint8_t *&data, unsigned &size, bool &patched) const;
bool load_ram (const char *filename, uint8_t *&data, unsigned size, uint8_t init_value) const;
enum CompressionMode {
CompressionNone, //always load without compression
CompressionInspect, //use file header inspection
CompressionAuto, //use file extension or file header inspection (configured by user)
};
bool load_file(const char *fn, uint8 *&data, unsigned &size, CompressionMode compression = CompressionNone) const;
bool save_file(const char *fn, uint8 *data, unsigned size) const;
bool apply_patch(const uint8_t *pdata, unsigned psize, uint8_t *&data, unsigned &size) const;
string modify_extension(const char *filename, const char *extension) const;
string get_filename(const char *source, const char *extension, const char *path) const;
struct {
string filename;
uint8_t *rom, *ram, *rtc;
unsigned rom_size, ram_size, rtc_size;
} cart;
struct {
string filename;
uint8_t *ram;
unsigned ram_size;
} bs;
struct {
string filename;
uint8_t *rom, *ram;
unsigned rom_size, ram_size;
} stA, stB;
};
namespace memory {
extern MappedRAM cartrom, cartram, cartrtc;
extern MappedRAM bscram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
};
extern Cartridge cartridge;

View File

@@ -1,109 +0,0 @@
#ifdef CART_CPP
#include "../reader/filereader.hpp"
#if defined(GZIP_SUPPORT)
#include "../reader/gzreader.hpp"
#include "../reader/zipreader.hpp"
#endif
#if defined(JMA_SUPPORT)
#include "../reader/jmareader.hpp"
#endif
string Cartridge::modify_extension(const char *filename_, const char *extension) const {
string filename = filename_;
int i;
for(i = strlen(filename); i >= 0; i--) {
if(filename[i] == '.') break;
if(filename[i] == '/') break;
if(filename[i] == '\\') break;
}
if(i > 0 && filename[i] == '.') filename[i] = 0;
return filename << "." << extension;
}
string Cartridge::get_filename(const char *source, const char *extension, const char *path) const {
return filepath(modify_extension(source, extension), path);
}
bool Cartridge::load_file(const char *fn, uint8 *&data, unsigned &size, CompressionMode compression) const {
if(file::exists(fn) == false) return false;
Reader::Type filetype = Reader::Normal;
if(compression == CompressionInspect) filetype = Reader::detect(fn, true);
if(compression == CompressionAuto) filetype = Reader::detect(fn, snes.config.file.autodetect_type);
switch(filetype) { default:
case Reader::Normal: {
FileReader ff(fn);
if(!ff.ready()) return false;
size = ff.size();
data = ff.read();
} break;
#ifdef GZIP_SUPPORT
case Reader::GZIP: {
GZReader gf(fn);
if(!gf.ready()) return false;
size = gf.size();
data = gf.read();
} break;
case Reader::ZIP: {
ZipReader zf(fn);
if(!zf.ready()) return false;
size = zf.size();
data = zf.read();
} break;
#endif
#ifdef JMA_SUPPORT
case Reader::JMA: {
try {
JMAReader jf(fn);
size = jf.size();
data = jf.read();
} catch(JMA::jma_errors jma_error) {
return false;
}
} break;
#endif
}
return true;
}
bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t *&data, unsigned &size) const {
uint8_t *outdata = 0;
unsigned outsize;
ups patcher;
ups::result result = patcher.apply(pdata, psize, data, size, outdata, outsize);
bool apply = false;
if(result == ups::ok) apply = true;
if(snes.config.file.bypass_patch_crc32 == true) {
if(result == ups::input_crc32_invalid) apply = true;
if(result == ups::output_crc32_invalid) apply = true;
}
//if patch application was successful, replace old data, size with new data, size
if(apply == true) {
delete[] data;
data = new uint8_t[size = outsize];
memcpy(data, outdata, outsize);
}
if(outdata) delete[] outdata;
return apply;
}
bool Cartridge::save_file(const char *fn, uint8 *data, unsigned size) const {
file fp;
if(!fp.open(fn, file::mode_write)) return false;
fp.write(data, size);
fp.close();
return true;
}
#endif

View File

@@ -1,245 +0,0 @@
#ifdef CART_CPP
//================
//Normal cartridge
//================
bool Cartridge::load_normal(const char *base) {
uint8_t *data;
unsigned size;
bool patch_applied;
cart.filename = base;
load_begin(ModeNormal);
if(load_image(base, data, size, patch_applied) == false) return false;
snes.config.path.current = basepath(cart.filename);
if(patch_applied) set(patched, true);
cartinfo_t cartinfo;
read_header(cartinfo, cart.rom = data, cart.rom_size = size);
set_cartinfo(cartinfo);
if(cartinfo.ram_size > 0) {
load_ram(get_filename(base, "srm", snes.config.path.save), cart.ram, cart.ram_size = cartinfo.ram_size, 0xff);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
load_ram(get_filename(base, "rtc", snes.config.path.save), cart.rtc, cart.rtc_size = 20, 0x00);
}
load_end();
set(name, basename(base));
return true;
}
void Cartridge::unload_normal() {
if(cart.ram) save_file(get_filename(cart.filename, "srm", snes.config.path.save), cart.ram, cart.ram_size);
if(cart.rtc) save_file(get_filename(cart.filename, "rtc", snes.config.path.save), cart.rtc, cart.rtc_size);
}
//======================
//BS-X slotted cartridge
//======================
bool Cartridge::load_bsx_slotted(const char *base, const char *slot) {
uint8_t *data;
unsigned size;
bool patch_applied;
cart.filename = base;
bs.filename = slot;
load_begin(ModeBsxSlotted);
if(load_image(base, data, size, patch_applied) == false) return false;
snes.config.path.current = basepath(cart.filename);
if(patch_applied) set(patched, true);
cartinfo_t cartinfo;
read_header(cartinfo, cart.rom = data, cart.rom_size = size);
set_cartinfo(cartinfo);
if(load_image(slot, data, size, patch_applied) == true) {
set(bsx_flash_loaded, true);
if(patch_applied) set(patched, true);
bs.ram = data;
bs.ram_size = size;
}
if(cartinfo.ram_size > 0) {
load_ram(get_filename(base, "srm", snes.config.path.save), cart.ram, cart.ram_size = cartinfo.ram_size, 0xff);
}
load_end();
string filename = basename(base);
if(*slot) filename << " + " << basename(slot);
set(name, filename);
return true;
}
void Cartridge::unload_bsx_slotted() {
if(cart.ram) save_file(get_filename(cart.filename, "srm", snes.config.path.save), cart.ram, cart.ram_size);
}
//====================
//BS-X flash cartridge
//====================
bool Cartridge::load_bsx(const char *base, const char *slot) {
uint8_t *data;
unsigned size;
bool patch_applied;
cart.filename = base;
bs.filename = slot;
load_begin(ModeBsx);
if(load_image(base, data, size, patch_applied) == false) return false;
snes.config.path.current = basepath(cart.filename);
if(patch_applied) set(patched, true);
cartinfo_t cartinfo;
read_header(cartinfo, cart.rom = data, cart.rom_size = size);
set_cartinfo(cartinfo);
cart.ram = 0;
cart.ram_size = 0;
memset(bsxcart.sram.handle (), 0x00, bsxcart.sram.size ());
memset(bsxcart.psram.handle(), 0x00, bsxcart.psram.size());
if(load_file(get_filename(base, "srm", snes.config.path.save), data, size, CompressionNone) == true) {
memcpy(bsxcart.sram.handle (), data, min(bsxcart.sram.size (), size));
delete[] data;
}
if(load_file(get_filename(base, "psr", snes.config.path.save), data, size, CompressionNone) == true) {
memcpy(bsxcart.psram.handle(), data, min(bsxcart.psram.size(), size));
delete[] data;
}
if(load_image(slot, data, size, patch_applied) == true) {
set(bsx_flash_loaded, true);
if(patch_applied) set(patched, true);
bs.ram = data;
bs.ram_size = size;
}
load_end();
set(name, !*slot ? basename(base) : basename(slot));
return true;
}
void Cartridge::unload_bsx() {
save_file(get_filename(cart.filename, "srm", snes.config.path.save), bsxcart.sram.handle (), bsxcart.sram.size ());
save_file(get_filename(cart.filename, "psr", snes.config.path.save), bsxcart.psram.handle(), bsxcart.psram.size());
}
//============================
//Sufami Turbo flash cartridge
//============================
bool Cartridge::load_sufami_turbo(const char *base, const char *slotA, const char *slotB) {
uint8_t *data;
unsigned size;
bool patch_applied;
cart.filename = base;
stA.filename = slotA;
stB.filename = slotB;
load_begin(ModeSufamiTurbo);
if(load_image(base, data, size, patch_applied) == false) return false;
snes.config.path.current = basepath(cart.filename);
if(patch_applied) set(patched, true);
cartinfo_t cartinfo;
read_header(cartinfo, cart.rom = data, cart.rom_size = size);
set_cartinfo(cartinfo);
if(load_image(slotA, data, size, patch_applied) == true) {
if(patch_applied) set(patched, true);
stA.rom = new(zeromemory) uint8_t[stA.rom_size = 0x100000];
memcpy(stA.rom, data, min(size, stA.rom_size));
delete[] data;
load_ram(get_filename(slotA, "srm", snes.config.path.save), stA.ram, stA.ram_size = 0x020000, 0xff);
}
if(load_image(slotB, data, size, patch_applied) == true) {
if(patch_applied) set(patched, true);
stB.rom = new(zeromemory) uint8_t[stB.rom_size = 0x100000];
memcpy(stB.rom, data, min(size, stB.rom_size));
delete[] data;
load_ram(get_filename(slotB, "srm", snes.config.path.save), stB.ram, stB.ram_size = 0x020000, 0xff);
}
load_end();
string filename;
if(!*slotA && !*slotB) filename << basename(base);
else if( *slotA && !*slotB) filename << basename(slotA);
else if(!*slotA && *slotB) filename << basename(slotB);
else filename << basename(slotA) << " + " << basename(slotB);
set(name, filename);
return true;
}
void Cartridge::unload_sufami_turbo() {
if(stA.ram) save_file(get_filename(stA.filename, "srm", snes.config.path.save), stA.ram, stA.ram_size);
if(stB.ram) save_file(get_filename(stB.filename, "srm", snes.config.path.save), stB.ram, stB.ram_size);
}
//=================
//utility functions
//=================
Cartridge::Type Cartridge::detect_image_type(const char *filename) const {
uint8_t *data;
unsigned size;
bool patch_applied;
if(!load_image(filename, data, size, patch_applied)) return TypeUnknown;
cartinfo_t info;
read_header(info, data, size);
delete[] data;
return info.type;
}
bool Cartridge::load_image(const char *filename, uint8_t *&data, unsigned &size, bool &patched) const {
if(!filename || !*filename) return false;
if(!load_file(filename, data, size, CompressionAuto)) return false;
if((size & 0x7fff) == 512) {
//remove 512-byte header
memmove(data, data + 512, size -= 512);
}
uint8_t *pdata;
unsigned psize;
string path = (snes.config.path.patch == "" ? basepath(filename) : snes.config.path.patch);
if(load_file(get_filename(filename, "ups", path), pdata, psize, CompressionInspect) == true) {
bool result = apply_patch(pdata, psize, data, size);
delete[] pdata;
patched = result;
} else {
patched = false;
}
return true;
}
bool Cartridge::load_ram(const char *filename, uint8_t *&data, unsigned size, uint8_t init) const {
data = new uint8_t[size];
memset(data, init, size);
uint8_t *savedata;
unsigned savesize;
if(load_file(filename, savedata, savesize, CompressionNone) == false) return false;
memcpy(data, savedata, min(size, savesize));
delete[] savedata;
return true;
}
#endif

157
src/cartridge/cartridge.cpp Normal file
View File

@@ -0,0 +1,157 @@
#include <../base.hpp>
#define CARTRIDGE_CPP
namespace SNES {
#include "header.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
MappedRAM gbrom, gbram;
};
Cartridge cartridge;
void Cartridge::load(Mode cartridge_mode) {
cartinfo_t cartinfo;
read_header(cartinfo, memory::cartrom.data(), memory::cartrom.size());
set_cartinfo(cartinfo);
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(new(zeromemory) uint8_t[cartinfo.ram_size], cartinfo.ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
memory::cartrtc.map(new(zeromemory) uint8_t[20], 20);
}
if(mode() == ModeBsx) {
memory::bsxram.map (new(zeromemory) uint8_t[ 32 * 1024], 32 * 1024);
memory::bsxpram.map(new(zeromemory) uint8_t[512 * 1024], 512 * 1024);
}
if(mode() == ModeSufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
}
if(mode() == ModeSuperGameBoy) {
if(memory::gbrom.data()) memory::gbram.map(new(zeromemory) uint8_t[64 * 1024], 64 * 1024);
}
memory::cartrom.write_protect(true);
memory::cartram.write_protect(false);
memory::cartrtc.write_protect(false);
memory::bsxflash.write_protect(true);
memory::bsxram.write_protect(false);
memory::bsxpram.write_protect(false);
memory::stArom.write_protect(true);
memory::stAram.write_protect(false);
memory::stBrom.write_protect(true);
memory::stBram.write_protect(false);
memory::gbrom.write_protect(true);
memory::gbram.write_protect(false);
bus.load_cart();
set(loaded, true);
}
void Cartridge::unload() {
memory::cartrom.reset();
memory::cartram.reset();
memory::cartrtc.reset();
memory::bsxflash.reset();
memory::bsxram.reset();
memory::bsxpram.reset();
memory::stArom.reset();
memory::stAram.reset();
memory::stBrom.reset();
memory::stBram.reset();
memory::gbrom.reset();
memory::gbram.reset();
if(loaded() == false) return;
bus.unload_cart();
set(loaded, false);
}
Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const {
cartinfo_t info;
read_header(info, data, size);
return info.type;
}
Cartridge::Cartridge() {
set(loaded, false);
unload();
}
Cartridge::~Cartridge() {
unload();
}
void Cartridge::set_cartinfo(const Cartridge::cartinfo_t &source) {
set(region, source.region);
set(mapper, source.mapper);
set(dsp1_mapper, source.dsp1_mapper);
set(has_bsx_slot, source.bsx_slot);
set(has_superfx, source.superfx);
set(has_sa1, source.sa1);
set(has_srtc, source.srtc);
set(has_sdd1, source.sdd1);
set(has_spc7110, source.spc7110);
set(has_spc7110rtc, source.spc7110rtc);
set(has_cx4, source.cx4);
set(has_dsp1, source.dsp1);
set(has_dsp2, source.dsp2);
set(has_dsp3, source.dsp3);
set(has_dsp4, source.dsp4);
set(has_obc1, source.obc1);
set(has_st010, source.st010);
set(has_st011, source.st011);
set(has_st018, source.st018);
}
//==========
//cartinfo_t
//==========
void Cartridge::cartinfo_t::reset() {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = 0;
ram_size = 0;
bsx_slot = false;
superfx = false;
sa1 = false;
srtc = false;
sdd1 = false;
spc7110 = false;
spc7110rtc = false;
cx4 = false;
dsp1 = false;
dsp2 = false;
dsp3 = false;
dsp4 = false;
obc1 = false;
st010 = false;
st011 = false;
st018 = false;
}
Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
};

131
src/cartridge/cartridge.hpp Normal file
View File

@@ -0,0 +1,131 @@
class Cartridge : public property {
public:
enum Mode {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
ModeSufamiTurbo,
ModeSuperGameBoy,
};
enum Type {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoyBios,
TypeGameBoy,
TypeUnknown,
};
enum Region {
NTSC,
PAL,
};
enum MemoryMapper {
LoROM,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
//properties can be read via operator(), eg "if(cartridge.loaded() == true)";
//warning: if loaded() == false, no other property is considered valid!
property_t<bool> loaded; //is a base cartridge inserted?
property_t<Mode> mode;
property_t<Region> region;
property_t<MemoryMapper> mapper;
property_t<DSP1MemoryMapper> dsp1_mapper;
property_t<bool> has_bsx_slot;
property_t<bool> has_superfx;
property_t<bool> has_sa1;
property_t<bool> has_srtc;
property_t<bool> has_sdd1;
property_t<bool> has_spc7110, has_spc7110rtc;
property_t<bool> has_cx4;
property_t<bool> has_dsp1, has_dsp2, has_dsp3, has_dsp4;
property_t<bool> has_obc1;
property_t<bool> has_st010, has_st011, has_st018;
//main interface
void load(Mode);
//void read();
//void load();
void unload();
Type detect_image_type(uint8_t *data, unsigned size) const;
Cartridge();
~Cartridge();
private:
struct cartinfo_t {
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
unsigned rom_size, ram_size;
bool bsx_slot;
bool superfx;
bool sa1;
bool srtc;
bool sdd1;
bool spc7110, spc7110rtc;
bool cx4;
bool dsp1, dsp2, dsp3, dsp4;
bool obc1;
bool st010, st011, st018;
void reset();
cartinfo_t();
};
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
RomSize = 0x17,
RamSize = 0x18,
CartRegion = 0x19,
Company = 0x1a,
Version = 0x1b,
Complement = 0x1c, //inverse checksum
Checksum = 0x1e,
ResetVector = 0x3c,
};
void read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const;
unsigned find_header(const uint8_t *data, unsigned size) const;
unsigned score_header(const uint8_t *data, unsigned size, unsigned addr) const;
void set_cartinfo(const cartinfo_t&);
};
namespace memory {
extern MappedRAM cartrom, cartram, cartrtc;
extern MappedRAM bsxflash, bsxram, bsxpram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
extern MappedRAM gbrom, gbram;
};
extern Cartridge cartridge;

View File

@@ -1,8 +1,32 @@
#ifdef CART_CPP
#ifdef CARTRIDGE_CPP
void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const {
info.reset();
unsigned index = find_header(data, size);
//=====================
//detect Game Boy carts
//=====================
if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
info.type = TypeGameBoy;
return;
}
}
const unsigned index = find_header(data, size);
const uint8 mapper = data[index + Mapper];
const uint8 rom_type = data[index + RomType];
const uint8 rom_size = data[index + RomSize];
const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f;
info.ram_size = 1024 << (data[index + RamSize] & 7);
if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
//0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
@@ -37,16 +61,19 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
return; //RAM size handled internally by load_cart_st();
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
info.type = TypeSuperGameBoyBios;
return;
}
//=====================
//detect standard carts
//=====================
const uint8 mapper = data[index + Mapper];
const uint8 rom_type = data[index + RomType];
const uint8 rom_size = data[index + RomSize];
const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f;
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') {
if(data[index - 11] == 'J') {
@@ -89,6 +116,9 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true;
info.mapper = SuperFXROM;
info.ram_size = 1024 << (data[index - 3] & 7);
if(info.ram_size == 1024) info.ram_size = 0;
}
if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
@@ -163,15 +193,6 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(mapper == 0x30 && rom_type == 0xf5) {
info.st018 = true;
}
if(data[index + RamSize] & 7) {
info.ram_size = 1024 << (data[index + RamSize] & 7);
} else {
info.ram_size = 0;
}
//0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
}
unsigned Cartridge::find_header(const uint8_t *data, unsigned size) const {

View File

@@ -1,3 +1,5 @@
@mingw32-make platform=win compiler=mingw32-gcc
::@mingw32-make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true
@mingw32-make
::@mingw32-make enable_gzip=true enable_jma=true
@pause

View File

@@ -1,2 +0,0 @@
#make platform=x compiler=gcc
make platform=x compiler=gcc enable_gzip=true enable_jma=true

View File

@@ -1,392 +1,391 @@
#include <../base.hpp>
Cheat cheat;
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
enabled = source.enabled;
code = source.code;
desc = source.desc;
count = source.count;
addr.reset();
data.reset();
for(unsigned n = 0; n < count; n++) {
addr[n] = source.addr[n];
data[n] = source.data[n];
}
return *this;
}
//used to sort cheat code list by description
bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
return strcmp(desc, source.desc) < 0;
}
//parse item ("0123-4567+89AB-CDEF"), return cheat_t item
//return true if code is valid, false otherwise
bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
item.enabled = false;
item.count = 0;
lstring list;
list.split("+", s);
for(unsigned n = 0; n < list.size(); n++) {
unsigned addr;
uint8_t data;
type_t type;
if(decode(list[n], addr, data, type) == false) return false;
item.addr[item.count] = addr;
item.data[item.count] = data;
item.count++;
}
return true;
}
//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
//returns true if cheat code was found, false if it was not.
//when true, cheat code substitution value is stored in data.
bool Cheat::read(unsigned addr, uint8_t &data) const {
addr = mirror_address(addr);
for(unsigned i = 0; i < code.size(); i++) {
if(enabled(i) == false) continue;
for(unsigned n = 0; n < code[i].count; n++) {
if(addr == mirror_address(code[i].addr[n])) {
data = code[i].data[n];
return true;
}
}
}
//code not found, or code is disabled
return false;
}
//==============
//master control
//==============
//global cheat system enable/disable:
//if disabled, *all* cheat codes are disabled;
//otherwise only individually disabled codes are.
bool Cheat::enabled() const {
return cheat_system_enabled;
}
void Cheat::enable() {
cheat_system_enabled = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
}
void Cheat::disable() {
cheat_system_enabled = false;
cheat_enabled = false;
}
//================================
//cheat list manipulation routines
//================================
bool Cheat::add(bool enable, const char *code_, const char *desc_) {
cheat_t item;
if(decode(code_, item) == false) return false;
unsigned i = code.size();
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
return true;
}
bool Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
cheat_t item;
if(decode(code_, item) == false) return false;
//disable current code and clear from code lookup table
code[i].enabled = false;
update(code[i]);
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
return true;
}
bool Cheat::remove(unsigned i) {
unsigned size = code.size();
if(i >= size) return false; //also verifies size cannot be < 1
for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
code.resize(size - 1);
update_cheat_status();
return true;
}
bool Cheat::get(unsigned i, cheat_t &item) const {
if(i >= code.size()) return false;
item = code[i];
decode_description(item.desc);
return true;
}
//==============================
//cheat status modifier routines
//==============================
bool Cheat::enabled(unsigned i) const {
return (i < code.size() ? code[i].enabled : false);
}
void Cheat::enable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = true;
update(code[i]);
update_cheat_status();
}
void Cheat::disable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = false;
update(code[i]);
update_cheat_status();
}
//===============================
//cheat file load / save routines
//
//file format:
//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
//...
//===============================
bool Cheat::load(const char *fn) {
string data;
if(!data.readfile(fn)) return false;
data.replace("\r\n", "\n");
data.qreplace(" ", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
part.qsplit(",", line[i]);
if(part.size() != 3) continue;
trim(part[0], "\"");
add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]);
}
return true;
}
bool Cheat::save(const char *fn) const {
file fp;
if(!fp.open(fn, file::mode_write)) return false;
for(unsigned i = 0; i < code.size(); i++) {
fp.print(string()
<< "\"" << code[i].desc << "\", "
<< (code[i].enabled ? "enabled, " : "disabled, ")
<< code[i].code << "\r\n");
}
fp.close();
return true;
}
void Cheat::clear() {
cheat_enabled_code_exists = false;
memset(mask, 0, 0x200000);
code.reset();
}
Cheat::Cheat() : cheat_system_enabled(true) {
clear();
}
//==================
//internal functions
//==================
//string <> binary code translation routines
//decode() "7e123456" -> 0x7e123456
//encode() 0x7e123456 -> "7e123456"
bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
string t = s;
strlower(t);
#define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f'))
if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
//strip ':'
if(strlen(t) == 9 && t[6] == ':') t = string() << substr(t, 0, 6) << substr(t, 7);
//validate input
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
type = ProActionReplay;
unsigned r = strhex((const char*)t);
addr = r >> 8;
data = r & 0xff;
return true;
} else if(strlen(t) == 9 && t[4] == '-') {
//strip '-'
t = string() << substr(t, 0, 4) << substr(t, 5);
//validate input
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
type = GameGenie;
strtr(t, "df4709156bc8a23e", "0123456789abcdef");
unsigned r = strhex((const char*)t);
//8421 8421 8421 8421 8421 8421
//abcd efgh ijkl mnop qrst uvwx
//ijkl qrst opab cduv wxef ghmn
addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22)
| (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20)
| (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18)
| (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16)
| (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14)
| (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12)
| (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10)
| (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8)
| (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6)
| (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4)
| (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2)
| (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
data = r >> 24;
return true;
} else {
return false;
}
}
bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
char t[16];
if(type == ProActionReplay) {
sprintf(t, "%.6x%.2x", addr, data);
s = t;
return true;
} else if(type == GameGenie) {
unsigned r = addr;
addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22)
| (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20)
| (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18)
| (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16)
| (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14)
| (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12)
| (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10)
| (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8)
| (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6)
| (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4)
| (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2)
| (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
sprintf(t, "%.2x%.2x-%.4x", data, addr >> 16, addr & 0xffff);
strtr(t, "0123456789abcdef", "df4709156bc8a23e");
s = t;
return true;
} else {
return false;
}
}
//speed up S-CPU memory reads by disabling cheat code lookup when either:
//a) cheat system is disabled by user, or b) no enabled cheat codes exist
void Cheat::update_cheat_status() {
for(unsigned i = 0; i < code.size(); i++) {
if(code[i].enabled) {
cheat_enabled_code_exists = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
return;
}
}
cheat_enabled_code_exists = false;
cheat_enabled = false;
}
//address lookup table manipulation and mirroring
//mirror_address() 0x000000 -> 0x7e0000
//set() enable specified address, mirror accordingly
//clear() disable specified address, mirror accordingly
unsigned Cheat::mirror_address(unsigned addr) const {
if((addr & 0x40e000) != 0x0000) return addr;
//8k WRAM mirror
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
return (0x7e0000 + (addr & 0x1fff));
}
//updates mask[] table enabled bits;
//must be called after modifying item.enabled state.
void Cheat::update(const cheat_t &item) {
for(unsigned n = 0; n < item.count; n++) {
(item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
}
}
void Cheat::set(unsigned addr) {
addr = mirror_address(addr);
mask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
}
}
}
void Cheat::clear(unsigned addr) {
addr = mirror_address(addr);
//if there is more than one cheat code using the same address,
//(eg with a different override value) then do not clear code
//lookup table entry.
uint8_t r;
if(read(addr, r) == true) return;
mask[addr >> 3] &= ~(1 << (addr & 7));
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
}
}
}
//these two functions are used to safely store description text inside .cfg file format.
string& Cheat::encode_description(string &desc) const {
desc.replace("\"", "\\q");
desc.replace("\n", "\\n");
return desc;
}
string& Cheat::decode_description(string &desc) const {
desc.replace("\\q", "\"");
desc.replace("\\n", "\n");
return desc;
}
#include <../base.hpp>
#define CHEAT_CPP
namespace SNES {
Cheat cheat;
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
enabled = source.enabled;
code = source.code;
desc = source.desc;
count = source.count;
addr.reset();
data.reset();
for(unsigned n = 0; n < count; n++) {
addr[n] = source.addr[n];
data[n] = source.data[n];
}
return *this;
}
//used to sort cheat code list by description
bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
return strcmp(desc, source.desc) < 0;
}
//parse item ("0123-4567+89AB-CDEF"), return cheat_t item
//return true if code is valid, false otherwise
bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
item.enabled = false;
item.count = 0;
lstring list;
list.split("+", s);
for(unsigned n = 0; n < list.size(); n++) {
unsigned addr;
uint8_t data;
type_t type;
if(decode(list[n], addr, data, type) == false) return false;
item.addr[item.count] = addr;
item.data[item.count] = data;
item.count++;
}
return true;
}
//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
//returns true if cheat code was found, false if it was not.
//when true, cheat code substitution value is stored in data.
bool Cheat::read(unsigned addr, uint8_t &data) const {
addr = mirror_address(addr);
for(unsigned i = 0; i < code.size(); i++) {
if(enabled(i) == false) continue;
for(unsigned n = 0; n < code[i].count; n++) {
if(addr == mirror_address(code[i].addr[n])) {
data = code[i].data[n];
return true;
}
}
}
//code not found, or code is disabled
return false;
}
//==============
//master control
//==============
//global cheat system enable/disable:
//if disabled, *all* cheat codes are disabled;
//otherwise only individually disabled codes are.
bool Cheat::enabled() const {
return cheat_system_enabled;
}
void Cheat::enable() {
cheat_system_enabled = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
}
void Cheat::disable() {
cheat_system_enabled = false;
cheat_enabled = false;
}
//================================
//cheat list manipulation routines
//================================
bool Cheat::add(bool enable, const char *code_, const char *desc_) {
cheat_t item;
if(decode(code_, item) == false) return false;
unsigned i = code.size();
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
return true;
}
bool Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
cheat_t item;
if(decode(code_, item) == false) return false;
//disable current code and clear from code lookup table
code[i].enabled = false;
update(code[i]);
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
return true;
}
bool Cheat::remove(unsigned i) {
unsigned size = code.size();
if(i >= size) return false; //also verifies size cannot be < 1
for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
code.resize(size - 1);
update_cheat_status();
return true;
}
bool Cheat::get(unsigned i, cheat_t &item) const {
if(i >= code.size()) return false;
item = code[i];
decode_description(item.desc);
return true;
}
//==============================
//cheat status modifier routines
//==============================
bool Cheat::enabled(unsigned i) const {
return (i < code.size() ? code[i].enabled : false);
}
void Cheat::enable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = true;
update(code[i]);
update_cheat_status();
}
void Cheat::disable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = false;
update(code[i]);
update_cheat_status();
}
//===============================
//cheat file load / save routines
//
//file format:
//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
//...
//===============================
void Cheat::load(string data) {
data.replace("\r\n", "\n");
data.qreplace(" ", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
part.qsplit(",", line[i]);
if(part.size() != 3) continue;
trim(part[0], "\"");
add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]);
}
}
string Cheat::save() const {
string data;
for(unsigned i = 0; i < code.size(); i++) {
data << "\"" << code[i].desc << "\", "
<< (code[i].enabled ? "enabled, " : "disabled, ")
<< code[i].code << "\r\n";
}
return data;
}
void Cheat::clear() {
cheat_enabled_code_exists = false;
memset(mask, 0, 0x200000);
code.reset();
}
Cheat::Cheat() : cheat_system_enabled(true) {
clear();
}
//==================
//internal functions
//==================
//string <> binary code translation routines
//decode() "7e123456" -> 0x7e123456
//encode() 0x7e123456 -> "7e123456"
bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
string t = s;
strlower(t);
#define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f'))
if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
//strip ':'
if(strlen(t) == 9 && t[6] == ':') t = string() << substr(t, 0, 6) << substr(t, 7);
//validate input
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
type = ProActionReplay;
unsigned r = strhex((const char*)t);
addr = r >> 8;
data = r & 0xff;
return true;
} else if(strlen(t) == 9 && t[4] == '-') {
//strip '-'
t = string() << substr(t, 0, 4) << substr(t, 5);
//validate input
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
type = GameGenie;
strtr(t, "df4709156bc8a23e", "0123456789abcdef");
unsigned r = strhex((const char*)t);
//8421 8421 8421 8421 8421 8421
//abcd efgh ijkl mnop qrst uvwx
//ijkl qrst opab cduv wxef ghmn
addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22)
| (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20)
| (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18)
| (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16)
| (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14)
| (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12)
| (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10)
| (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8)
| (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6)
| (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4)
| (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2)
| (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
data = r >> 24;
return true;
} else {
return false;
}
}
bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
char t[16];
if(type == ProActionReplay) {
sprintf(t, "%.6x%.2x", addr, data);
s = t;
return true;
} else if(type == GameGenie) {
unsigned r = addr;
addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22)
| (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20)
| (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18)
| (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16)
| (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14)
| (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12)
| (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10)
| (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8)
| (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6)
| (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4)
| (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2)
| (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
sprintf(t, "%.2x%.2x-%.4x", data, addr >> 16, addr & 0xffff);
strtr(t, "0123456789abcdef", "df4709156bc8a23e");
s = t;
return true;
} else {
return false;
}
}
//speed up S-CPU memory reads by disabling cheat code lookup when either:
//a) cheat system is disabled by user, or b) no enabled cheat codes exist
void Cheat::update_cheat_status() {
for(unsigned i = 0; i < code.size(); i++) {
if(code[i].enabled) {
cheat_enabled_code_exists = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
return;
}
}
cheat_enabled_code_exists = false;
cheat_enabled = false;
}
//address lookup table manipulation and mirroring
//mirror_address() 0x000000 -> 0x7e0000
//set() enable specified address, mirror accordingly
//clear() disable specified address, mirror accordingly
unsigned Cheat::mirror_address(unsigned addr) const {
if((addr & 0x40e000) != 0x0000) return addr;
//8k WRAM mirror
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
return (0x7e0000 + (addr & 0x1fff));
}
//updates mask[] table enabled bits;
//must be called after modifying item.enabled state.
void Cheat::update(const cheat_t &item) {
for(unsigned n = 0; n < item.count; n++) {
(item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
}
}
void Cheat::set(unsigned addr) {
addr = mirror_address(addr);
mask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
}
}
}
void Cheat::clear(unsigned addr) {
addr = mirror_address(addr);
//if there is more than one cheat code using the same address,
//(eg with a different override value) then do not clear code
//lookup table entry.
uint8_t r;
if(read(addr, r) == true) return;
mask[addr >> 3] &= ~(1 << (addr & 7));
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
}
}
}
//these two functions are used to safely store description text inside .cfg file format.
string& Cheat::encode_description(string &desc) const {
desc.replace("\"", "\\q");
desc.replace("\n", "\\n");
return desc;
}
string& Cheat::decode_description(string &desc) const {
desc.replace("\\q", "\"");
desc.replace("\\n", "\n");
return desc;
}
};

View File

@@ -1,69 +1,69 @@
class Cheat {
public:
enum type_t {
ProActionReplay,
GameGenie,
};
struct cheat_t {
bool enabled;
string code;
string desc;
unsigned count;
array<unsigned> addr;
array<uint8_t> data;
cheat_t& operator=(const cheat_t&);
bool operator<(const cheat_t&);
};
bool decode(const char *s, cheat_t &item) const;
bool read(unsigned addr, uint8_t &data) const;
bool enabled() const;
void enable();
void disable();
inline unsigned count() const { return code.size(); }
inline bool active() const { return cheat_enabled; }
inline bool exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); }
bool add(bool enable, const char *code, const char *desc);
bool edit(unsigned i, bool enable, const char *code, const char *desc);
bool remove(unsigned i);
bool get(unsigned i, cheat_t &item) const;
bool enabled(unsigned i) const;
void enable(unsigned i);
void disable(unsigned i);
bool load(const char *fn);
bool save(const char *fn) const;
void clear();
Cheat();
private:
bool cheat_enabled; //cheat_enabled == (cheat_enabled_code_exists && cheat_system_enabled);
bool cheat_enabled_code_exists;
bool cheat_system_enabled;
uint8_t mask[0x200000];
vector<cheat_t> code;
bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const;
bool encode(string &str, unsigned addr, uint8_t data, type_t type) const;
void update_cheat_status();
unsigned mirror_address(unsigned addr) const;
void update(const cheat_t& item);
void set(unsigned addr);
void clear(unsigned addr);
string& encode_description(string &desc) const;
string& decode_description(string &desc) const;
};
extern Cheat cheat;
class Cheat {
public:
enum type_t {
ProActionReplay,
GameGenie,
};
struct cheat_t {
bool enabled;
string code;
string desc;
unsigned count;
array<unsigned> addr;
array<uint8_t> data;
cheat_t& operator=(const cheat_t&);
bool operator<(const cheat_t&);
};
bool decode(const char *s, cheat_t &item) const;
bool read(unsigned addr, uint8_t &data) const;
bool enabled() const;
void enable();
void disable();
inline unsigned count() const { return code.size(); }
inline bool active() const { return cheat_enabled; }
inline bool exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); }
bool add(bool enable, const char *code, const char *desc);
bool edit(unsigned i, bool enable, const char *code, const char *desc);
bool remove(unsigned i);
bool get(unsigned i, cheat_t &item) const;
bool enabled(unsigned i) const;
void enable(unsigned i);
void disable(unsigned i);
void load(string data);
string save() const;
void clear();
Cheat();
private:
bool cheat_enabled; //cheat_enabled == (cheat_enabled_code_exists && cheat_system_enabled);
bool cheat_enabled_code_exists;
bool cheat_system_enabled;
uint8_t mask[0x200000];
vector<cheat_t> code;
bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const;
bool encode(string &str, unsigned addr, uint8_t data, type_t type) const;
void update_cheat_status();
unsigned mirror_address(unsigned addr) const;
void update(const cheat_t& item);
void set(unsigned addr);
void clear(unsigned addr);
string& encode_description(string &desc) const;
string& decode_description(string &desc) const;
};
extern Cheat cheat;

View File

@@ -1,8 +1,10 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#define BSX_CPP
#include "bsx.hpp"
#include "bsx_base.cpp"
#include "bsx_cart.cpp"
#include "bsx_flash.cpp"
#include <../base.hpp>
#define BSX_CPP
namespace SNES {
#include "bsx_base.cpp"
#include "bsx_cart.cpp"
#include "bsx_flash.cpp"
};

View File

@@ -1,77 +1,71 @@
class BSXBase : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
struct {
uint8 r2188, r2189, r218a, r218b;
uint8 r218c, r218d, r218e, r218f;
uint8 r2190, r2191, r2192, r2193;
uint8 r2194, r2195, r2196, r2197;
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
} regs;
};
class BSXCart : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
MappedRAM sram;
MappedRAM psram;
BSXCart();
~BSXCart();
private:
uint8 *sram_data; //256kbit SRAM
uint8 *psram_data; // 4mbit PSRAM
struct {
uint8 r[16];
} regs;
void update_memory_map();
};
class BSXFlash : public Memory {
public:
void init();
void enable();
void power();
void reset();
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
struct {
unsigned command;
uint8 write_old;
uint8 write_new;
bool flash_enable;
bool read_enable;
bool write_enable;
} regs;
};
extern BSXBase bsxbase;
extern BSXCart bsxcart;
extern BSXFlash bsxflash;
class BSXBase : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
struct {
uint8 r2188, r2189, r218a, r218b;
uint8 r218c, r218d, r218e, r218f;
uint8 r2190, r2191, r2192, r2193;
uint8 r2194, r2195, r2196, r2197;
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
} regs;
};
class BSXCart : public MMIO {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
BSXCart();
~BSXCart();
private:
struct {
uint8 r[16];
} regs;
void update_memory_map();
};
class BSXFlash : public Memory {
public:
void init();
void enable();
void power();
void reset();
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
private:
struct {
unsigned command;
uint8 write_old;
uint8 write_new;
bool flash_enable;
bool read_enable;
bool write_enable;
} regs;
};
extern BSXBase bsxbase;
extern BSXCart bsxcart;
extern BSXFlash bsxflash;

View File

@@ -1,5 +1,7 @@
#ifdef BSX_CPP
BSXBase bsxbase;
void BSXBase::init() {
}
@@ -135,3 +137,4 @@ void BSXBase::mmio_write(unsigned addr, uint8 data) {
}
#endif

View File

@@ -1,5 +1,7 @@
#ifdef BSX_CPP
BSXCart bsxcart;
void BSXCart::init() {
}
@@ -20,7 +22,7 @@ void BSXCart::reset() {
}
void BSXCart::update_memory_map() {
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)memory::bsxpram;
if((regs.r[0x02] & 0x80) == 0x00) {
//LoROM mapping
@@ -35,16 +37,16 @@ void BSXCart::update_memory_map() {
}
if(regs.r[0x03] & 0x80) {
bus.map(Bus::MapLinear, 0x60, 0x6f, 0x0000, 0xffff, psram);
//bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram);
bus.map(Bus::MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
//bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x05] & 0x80) == 0x00) {
bus.map(Bus::MapLinear, 0x40, 0x4f, 0x0000, 0xffff, psram);
bus.map(Bus::MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x06] & 0x80) == 0x00) {
bus.map(Bus::MapLinear, 0x50, 0x5f, 0x0000, 0xffff, psram);
bus.map(Bus::MapLinear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
}
if(regs.r[0x07] & 0x80) {
@@ -55,8 +57,8 @@ void BSXCart::update_memory_map() {
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
}
bus.map(Bus::MapShadow, 0x20, 0x3f, 0x6000, 0x7fff, psram);
bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram);
bus.map(Bus::MapShadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
uint8 BSXCart::mmio_read(unsigned addr) {
@@ -66,7 +68,7 @@ uint8 BSXCart::mmio_read(unsigned addr) {
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return sram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
return memory::bsxram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
@@ -81,21 +83,15 @@ void BSXCart::mmio_write(unsigned addr, uint8 data) {
}
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
return sram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
return memory::bsxram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}
BSXCart::BSXCart() {
sram_data = new uint8_t[ 32 * 1024];
psram_data = new uint8_t[512 * 1024];
sram.map (sram_data, 32 * 1024);
psram.map(psram_data, 512 * 1024);
}
BSXCart::~BSXCart() {
delete[] sram_data;
delete[] psram_data;
}
#endif

View File

@@ -1,5 +1,7 @@
#ifdef BSX_CPP
BSXFlash bsxflash;
void BSXFlash::init() {}
void BSXFlash::enable() {}
@@ -15,10 +17,11 @@ void BSXFlash::reset() {
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
memory::bsxflash.write_protect(!regs.write_enable);
}
unsigned BSXFlash::size() const {
return memory::bscram.size();
return memory::bsxflash.size();
}
uint8 BSXFlash::read(unsigned addr) {
@@ -45,7 +48,7 @@ uint8 BSXFlash::read(unsigned addr) {
}
}
return memory::bscram.read(addr);
return memory::bsxflash.read(addr);
}
void BSXFlash::write(unsigned addr, uint8 data) {
@@ -64,11 +67,11 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.write_new = data;
if(regs.write_enable && regs.write_old == regs.write_new) {
return memory::bscram.write(addr, data);
return memory::bsxflash.write(addr, data);
}
} else {
if(regs.write_enable) {
return memory::bscram.write(addr, data);
return memory::bsxflash.write(addr, data);
}
}
@@ -107,7 +110,10 @@ void BSXFlash::write(unsigned addr, uint8 data) {
regs.read_enable = false;
regs.write_enable = false;
}
memory::bsxflash.write_protect(!regs.write_enable);
}
}
#endif

View File

@@ -1,12 +1,14 @@
#include "sa1/sa1.hpp"
#include "bsx/bsx.hpp"
#include "srtc/srtc.hpp"
#include "sdd1/sdd1.hpp"
#include "spc7110/spc7110.hpp"
#include "cx4/cx4.hpp"
#include "dsp1/dsp1.hpp"
#include "dsp2/dsp2.hpp"
#include "dsp3/dsp3.hpp"
#include "dsp4/dsp4.hpp"
#include "obc1/obc1.hpp"
#include "st010/st010.hpp"
#include "sgb/sgb.hpp"
#include "superfx/superfx.hpp"
#include "sa1/sa1.hpp"
#include "bsx/bsx.hpp"
#include "srtc/srtc.hpp"
#include "sdd1/sdd1.hpp"
#include "spc7110/spc7110.hpp"
#include "cx4/cx4.hpp"
#include "dsp1/dsp1.hpp"
#include "dsp2/dsp2.hpp"
#include "dsp3/dsp3.hpp"
#include "dsp4/dsp4.hpp"
#include "obc1/obc1.hpp"
#include "st010/st010.hpp"

View File

@@ -1,197 +1,202 @@
/*
C4 emulation
Used in Rockman X2/X3 (Megaman X2/X3)
Portions (c) anomie, Overload, zsKnight, Nach, byuu
*/
/*
C4 emulation
Used in Rockman X2/X3 (Megaman X2/X3)
Portions (c) anomie, Overload, zsKnight, Nach, byuu
*/
#include <../base.hpp>
#define CX4_CPP
#include "cx4.hpp"
#include "cx4data.cpp"
#include "cx4fn.cpp"
#include "cx4oam.cpp"
#include "cx4ops.cpp"
void Cx4::init() {}
void Cx4::enable() {}
uint32 Cx4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
}
void Cx4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64_t rx = x & 0xffffff;
int64_t ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 Cx4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 Cx4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void Cx4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i = start; i < 48; i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void Cx4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, bus.read(src++));
}
}
void Cx4::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00: op00(); break;
case 0x01: op01(); break;
case 0x05: op05(); break;
case 0x0d: op0d(); break;
case 0x10: op10(); break;
case 0x13: op13(); break;
case 0x15: op15(); break;
case 0x1f: op1f(); break;
case 0x22: op22(); break;
case 0x25: op25(); break;
case 0x2d: op2d(); break;
case 0x40: op40(); break;
case 0x54: op54(); break;
case 0x5c: op5c(); break;
case 0x5e: op5e(); break;
case 0x60: op60(); break;
case 0x62: op62(); break;
case 0x64: op64(); break;
case 0x66: op66(); break;
case 0x68: op68(); break;
case 0x6a: op6a(); break;
case 0x6c: op6c(); break;
case 0x6e: op6e(); break;
case 0x70: op70(); break;
case 0x72: op72(); break;
case 0x74: op74(); break;
case 0x76: op76(); break;
case 0x78: op78(); break;
case 0x7a: op7a(); break;
case 0x7c: op7c(); break;
case 0x89: op89(); break;
}
}
}
void Cx4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void Cx4::writew(uint16 addr, uint16 data) {
write(addr, data);
write(addr + 1, data >> 8);
}
void Cx4::writel(uint16 addr, uint32 data) {
write(addr, data);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 Cx4::read(unsigned addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return cpu.regs.mdr;
}
uint8 Cx4::readb(uint16 addr) {
return read(addr);
}
uint16 Cx4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 Cx4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void Cx4::power() {
reset();
}
void Cx4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
#define CX4_CPP
namespace SNES {
Cx4 cx4;
#include "cx4data.cpp"
#include "cx4fn.cpp"
#include "cx4oam.cpp"
#include "cx4ops.cpp"
void Cx4::init() {}
void Cx4::enable() {}
uint32 Cx4::ldr(uint8 r) {
uint16 addr = 0x0080 + (r * 3);
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
}
void Cx4::str(uint8 r, uint32 data) {
uint16 addr = 0x0080 + (r * 3);
reg[addr ] = (data);
reg[addr + 1] = (data >> 8);
reg[addr + 2] = (data >> 16);
}
void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
int64_t rx = x & 0xffffff;
int64_t ry = y & 0xffffff;
if(rx & 0x800000)rx |= ~0x7fffff;
if(ry & 0x800000)ry |= ~0x7fffff;
rx *= ry;
rl = (rx) & 0xffffff;
rh = (rx >> 24) & 0xffffff;
}
uint32 Cx4::sin(uint32 rx) {
r0 = rx & 0x1ff;
if(r0 & 0x100)r0 ^= 0x1ff;
if(r0 & 0x080)r0 ^= 0x0ff;
if(rx & 0x100) {
return sin_table[r0 + 0x80];
} else {
return sin_table[r0];
}
}
uint32 Cx4::cos(uint32 rx) {
return sin(rx + 0x080);
}
void Cx4::immediate_reg(uint32 start) {
r0 = ldr(0);
for(uint32 i = start; i < 48; i++) {
if((r0 & 0x0fff) < 0x0c00) {
ram[r0 & 0x0fff] = immediate_data[i];
}
r0++;
}
str(0, r0);
}
void Cx4::transfer_data() {
uint32 src;
uint16 dest, count;
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
count = (reg[0x43]) | (reg[0x44] << 8);
dest = (reg[0x45]) | (reg[0x46] << 8);
for(uint32 i=0;i<count;i++) {
write(dest++, bus.read(src++));
}
}
void Cx4::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 2;
return;
}
switch(data) {
case 0x00: op00(); break;
case 0x01: op01(); break;
case 0x05: op05(); break;
case 0x0d: op0d(); break;
case 0x10: op10(); break;
case 0x13: op13(); break;
case 0x15: op15(); break;
case 0x1f: op1f(); break;
case 0x22: op22(); break;
case 0x25: op25(); break;
case 0x2d: op2d(); break;
case 0x40: op40(); break;
case 0x54: op54(); break;
case 0x5c: op5c(); break;
case 0x5e: op5e(); break;
case 0x60: op60(); break;
case 0x62: op62(); break;
case 0x64: op64(); break;
case 0x66: op66(); break;
case 0x68: op68(); break;
case 0x6a: op6a(); break;
case 0x6c: op6c(); break;
case 0x6e: op6e(); break;
case 0x70: op70(); break;
case 0x72: op72(); break;
case 0x74: op74(); break;
case 0x76: op76(); break;
case 0x78: op78(); break;
case 0x7a: op7a(); break;
case 0x7c: op7c(); break;
case 0x89: op89(); break;
}
}
}
void Cx4::writeb(uint16 addr, uint8 data) {
write(addr, data);
}
void Cx4::writew(uint16 addr, uint16 data) {
write(addr, data);
write(addr + 1, data >> 8);
}
void Cx4::writel(uint16 addr, uint32 data) {
write(addr, data);
write(addr + 1, data >> 8);
write(addr + 2, data >> 16);
}
uint8 Cx4::read(unsigned addr) {
addr &= 0x1fff;
if(addr < 0x0c00) {
return ram[addr];
}
if(addr >= 0x1f00) {
return reg[addr & 0xff];
}
return cpu.regs.mdr;
}
uint8 Cx4::readb(uint16 addr) {
return read(addr);
}
uint16 Cx4::readw(uint16 addr) {
return read(addr) | (read(addr + 1) << 8);
}
uint32 Cx4::readl(uint16 addr) {
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
}
void Cx4::power() {
reset();
}
void Cx4::reset() {
memset(ram, 0, 0x0c00);
memset(reg, 0, 0x0100);
}
};

View File

@@ -1,97 +1,97 @@
class Cx4 : public Memory {
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
//
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern Cx4 cx4;
class Cx4 : public Memory {
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15;
static const uint8 immediate_data[48];
static const uint16 wave_data[40];
static const uint32 sin_table[256];
static const int16 SinTable[512];
static const int16 CosTable[512];
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
void C4DrawWireFrame();
void C4DoScaleRotate(int row_padding);
public:
uint32 ldr(uint8 r);
void str(uint8 r, uint32 data);
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
uint32 sin(uint32 rx);
uint32 cos(uint32 rx);
void transfer_data();
void immediate_reg(uint32 num);
void op00_00();
void op00_03();
void op00_05();
void op00_07();
void op00_08();
void op00_0b();
void op00_0c();
void op00();
void op01();
void op05();
void op0d();
void op10();
void op13();
void op15();
void op1f();
void op22();
void op25();
void op2d();
void op40();
void op54();
void op5c();
void op5e();
void op60();
void op62();
void op64();
void op66();
void op68();
void op6a();
void op6c();
void op6e();
void op70();
void op72();
void op74();
void op76();
void op78();
void op7a();
void op7c();
void op89();
uint8 readb(uint16 addr);
uint16 readw(uint16 addr);
uint32 readl(uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
//
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern Cx4 cx4;

View File

@@ -1,187 +1,187 @@
#ifdef CX4_CPP
const uint8 Cx4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
const uint16 Cx4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 Cx4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 Cx4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 Cx4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};
const uint8 Cx4::immediate_data[48] = {
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
};
#endif
const uint16 Cx4::wave_data[40] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
};
const uint32 Cx4::sin_table[256] = {
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
};
const int16 Cx4::SinTable[512] = {
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
};
const int16 Cx4::CosTable[512] = {
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};
#endif

View File

@@ -1,246 +1,246 @@
#ifdef CX4_CPP
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
//Wireframe Helpers
void Cx4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void Cx4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void Cx4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void Cx4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
}
point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
Color = bus.read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
}
X1 += X2;
Y1 += Y2;
}
}
void Cx4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}
#include <math.h>
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
#define sar(b, n) ((b) >> (n))
#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795
#endif
//Wireframe Helpers
void Cx4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
}
void Cx4::C4CalcWireFrame() {
C4WFXVal = C4WFX2Val - C4WFXVal;
C4WFYVal = C4WFY2Val - C4WFYVal;
if(abs(C4WFXVal) > abs(C4WFYVal)) {
C4WFDist = abs(C4WFXVal) + 1;
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
} else if(C4WFYVal != 0) {
C4WFDist = abs(C4WFYVal) + 1;
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
} else {
C4WFDist = 0;
}
}
void Cx4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
//Rotate Y
tanval = -(double)C4WFY2Val * PI * 2 / 128;
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
//Rotate Z
tanval = -(double)C4WFDist * PI * 2 / 128;
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
//Scale
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
}
void Cx4::C4DrawWireFrame() {
uint32 line = readl(0x1f80);
uint32 point1, point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
int32 tmp = line - 5;
while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
} else {
point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
}
point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
Color = bus.read(line + 4);
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
}
}
void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
//Transform coordinates
C4WFXVal = (int16)X1;
C4WFYVal = (int16)Y1;
C4WFZVal = Z1;
C4WFScale = read(0x1f90);
C4WFX2Val = read(0x1f86);
C4WFY2Val = read(0x1f87);
C4WFDist = read(0x1f88);
C4TransfWireFrame2();
X1 = (C4WFXVal + 48) << 8;
Y1 = (C4WFYVal + 48) << 8;
C4WFXVal = (int16)X2;
C4WFYVal = (int16)Y2;
C4WFZVal = Z2;
C4TransfWireFrame2();
X2 = (C4WFXVal + 48) << 8;
Y2 = (C4WFYVal + 48) << 8;
//Get line info
C4WFXVal = (int16)(X1 >> 8);
C4WFYVal = (int16)(Y1 >> 8);
C4WFX2Val = (int16)(X2 >> 8);
C4WFY2Val = (int16)(Y2 >> 8);
C4CalcWireFrame();
X2 = (int16)C4WFXVal;
Y2 = (int16)C4WFYVal;
//Render line
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
}
X1 += X2;
Y1 += Y2;
}
}
void Cx4::C4DoScaleRotate(int row_padding) {
int16 A, B, C, D;
//Calculate matrix
int32 XScale = readw(0x1f8f);
int32 YScale = readw(0x1f92);
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
D = 0;
} else {
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
}
//Calculate Pixel Resolution
uint8 w = read(0x1f89) & ~7;
uint8 h = read(0x1f8c) & ~7;
//Clear the output RAM
memset(ram, 0, (w + row_padding / 4) * h / 2);
int32 Cx = (int16)readw(0x1f83);
int32 Cy = (int16)readw(0x1f86);
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
//the function. We do Cx*A etc normally because the matrix parameters
//already have the fractional parts.
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
//Start loop
uint32 X, Y;
uint8 byte;
int32 outidx = 0;
uint8 bit = 0x80;
for(int32 y = 0; y < h; y++) {
X = LineX;
Y = LineY;
for(int32 x = 0; x < w; x++) {
if((X >> 12) >= w || (Y >> 12) >= h) {
byte = 0;
} else {
uint32 addr = (Y >> 12) * w + (X >> 12);
byte = read(0x600 + (addr >> 1));
if(addr & 1) { byte >>= 4; }
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
bit >>= 1;
if(!bit) {
bit = 0x80;
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
if(outidx & 0x10) {
outidx &= ~0x10;
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}
#endif

View File

@@ -1,223 +1,223 @@
#ifdef CX4_CPP
//Build OAM
void Cx4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
}
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
uint32 srcptr = 0x220;
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(bus.read(spraddr)) {
int16 x, y;
for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
x = (int8)bus.read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)bus.read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(bus.read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
//Scale and Rotate
void Cx4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void Cx4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void Cx4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void Cx4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void Cx4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
}
}
}
//Bitplane Wave
void Cx4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
for(int j = 0; j < 0x10; j++) {
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
}
}
//Build OAM
void Cx4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
}
#endif
uint16 globalx, globaly;
uint32 oamptr2;
int16 sprx, spry;
uint8 sprname, sprattr;
uint8 sprcount;
globalx = readw(0x621);
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
uint32 srcptr = 0x220;
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
sprx = readw(srcptr) - globalx;
spry = readw(srcptr + 2) - globaly;
sprname = ram[srcptr + 5];
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
uint32 spraddr = readl(srcptr + 7);
if(bus.read(spraddr)) {
int16 x, y;
for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
x = (int8)bus.read(spraddr + 1);
if(sprattr & 0x40) {
x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
x += sprx;
if(x >= -16 && x <= 272) {
y = (int8)bus.read(spraddr + 2);
if(sprattr & 0x80) {
y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
}
y += spry;
if(y >= -16 && y <= 224) {
ram[oamptr ] = (uint8)x;
ram[oamptr + 1] = (uint8)y;
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(bus.read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
} else if(sprcount > 0) {
ram[oamptr ] = (uint8)sprx;
ram[oamptr + 1] = (uint8)spry;
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
}
}
}
//Scale and Rotate
void Cx4::op00_03() {
C4DoScaleRotate(0);
}
//Transform Lines
void Cx4::op00_05() {
C4WFX2Val = read(0x1f83);
C4WFY2Val = read(0x1f86);
C4WFDist = read(0x1f89);
C4WFScale = read(0x1f8c);
//Transform Vertices
uint32 ptr = 0;
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
C4WFXVal = readw(ptr + 1);
C4WFYVal = readw(ptr + 5);
C4WFZVal = readw(ptr + 9);
C4TransfWireFrame();
//Displace
writew(ptr + 1, C4WFXVal + 0x80);
writew(ptr + 5, C4WFYVal + 0x50);
}
writew(0x600, 23);
writew(0x602, 0x60);
writew(0x605, 0x40);
writew(0x600 + 8, 23);
writew(0x602 + 8, 0x60);
writew(0x605 + 8, 0x40);
ptr = 0xb02;
uint32 ptr2 = 0;
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
C4CalcWireFrame();
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
writew(ptr2 + 0x602, C4WFXVal);
writew(ptr2 + 0x605, C4WFYVal);
}
}
//Scale and Rotate
void Cx4::op00_07() {
C4DoScaleRotate(64);
}
//Draw Wireframe
void Cx4::op00_08() {
C4DrawWireFrame();
}
//Disintegrate
void Cx4::op00_0b() {
uint8 width, height;
uint32 startx, starty;
uint32 srcptr;
uint32 x, y;
int32 scalex, scaley;
int32 cx, cy;
int32 i, j;
width = read(0x1f89);
height = read(0x1f8c);
cx = readw(0x1f80);
cy = readw(0x1f83);
scalex = (int16)readw(0x1f86);
scaley = (int16)readw(0x1f8f);
startx = -cx * scalex + (cx << 8);
starty = -cy * scaley + (cy << 8);
srcptr = 0x600;
for(i = 0; i < (width * height) >> 1; i++) {
write(i, 0);
}
for(y = starty, i = 0;i < height; i++, y += scaley) {
for(x = startx, j = 0;j < width; j++, x += scalex) {
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
}
}
}
//Bitplane Wave
void Cx4::op00_0c() {
uint32 destptr = 0;
uint32 waveptr = read(0x1f83);
uint16 mask1 = 0xc0c0;
uint16 mask2 = 0x3f3f;
for(int j = 0; j < 0x10; j++) {
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa00 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
do {
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
for(int i = 0; i < 40; i++) {
uint16 temp = readw(destptr + wave_data[i]) & mask2;
if(height >= 0) {
if(height < 8) {
temp |= mask1 & readw(0xa10 + height * 2);
} else {
temp |= mask1 & 0xff00;
}
}
writew(destptr + wave_data[i], temp);
height++;
}
waveptr = (waveptr + 1) & 0x7f;
mask1 = (mask1 >> 2) | (mask1 << 6);
mask2 = (mask2 >> 2) | (mask2 << 6);
} while(mask1 != 0xc0c0);
destptr += 16;
}
}
#endif

View File

@@ -1,226 +1,226 @@
#ifdef CX4_CPP
//Sprite Functions
void Cx4::op00() {
switch(reg[0x4d]) {
case 0x00:op00_00();break;
case 0x03:op00_03();break;
case 0x05:op00_05();break;
case 0x07:op00_07();break;
case 0x08:op00_08();break;
case 0x0b:op00_0b();break;
case 0x0c:op00_0c();break;
}
}
//Draw Wireframe
void Cx4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void Cx4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void Cx4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void Cx4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void Cx4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void Cx4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void Cx4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void Cx4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void Cx4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void Cx4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void Cx4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void Cx4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void Cx4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void Cx4::op5e() { immediate_reg( 0); }
void Cx4::op60() { immediate_reg( 3); }
void Cx4::op62() { immediate_reg( 6); }
void Cx4::op64() { immediate_reg( 9); }
void Cx4::op66() { immediate_reg(12); }
void Cx4::op68() { immediate_reg(15); }
void Cx4::op6a() { immediate_reg(18); }
void Cx4::op6c() { immediate_reg(21); }
void Cx4::op6e() { immediate_reg(24); }
void Cx4::op70() { immediate_reg(27); }
void Cx4::op72() { immediate_reg(30); }
void Cx4::op74() { immediate_reg(33); }
void Cx4::op76() { immediate_reg(36); }
void Cx4::op78() { immediate_reg(39); }
void Cx4::op7a() { immediate_reg(42); }
void Cx4::op7c() { immediate_reg(45); }
//Immediate ROM
void Cx4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}
//Sprite Functions
void Cx4::op00() {
switch(reg[0x4d]) {
case 0x00:op00_00();break;
case 0x03:op00_03();break;
case 0x05:op00_05();break;
case 0x07:op00_07();break;
case 0x08:op00_08();break;
case 0x0b:op00_0b();break;
case 0x0c:op00_0c();break;
}
}
#endif
//Draw Wireframe
void Cx4::op01() {
memset(ram + 0x300, 0, 2304);
C4DrawWireFrame();
}
//Propulsion
void Cx4::op05() {
int32 temp = 0x10000;
if(readw(0x1f83)) {
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
}
writew(0x1f80, temp);
}
//Set Vector length
void Cx4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
writew(0x1f89, C41FXVal);
writew(0x1f8c, C41FYVal);
}
//Triangle
void Cx4::op10() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
if(r1 & 0x8000)r1 |= ~0x7fff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 16) & 0xff;
r2 = (r2 << 8) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 16) & 0xff;
r3 = (r3 << 8) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Triangle
void Cx4::op13() {
r0 = ldr(0);
r1 = ldr(1);
r4 = r0 & 0x1ff;
mul(cos(r4), r1, r5, r2);
r5 = (r5 >> 8) & 0xffff;
r2 = (r2 << 16) + r5;
mul(sin(r4), r1, r5, r3);
r5 = (r5 >> 8) & 0xffff;
r3 = (r3 << 16) + r5;
str(0, r0);
str(1, r1);
str(2, r2);
str(3, r3);
str(4, r4);
str(5, r5);
}
//Pythagorean
void Cx4::op15() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
writew(0x1f80, C41FDist);
}
//Calculate distance
void Cx4::op1f() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {
C41FAngleRes += 0x100;
}
C41FAngleRes &= 0x1ff;
}
writew(0x1f86, C41FAngleRes);
}
//Trapezoid
void Cx4::op22() {
int16 angle1 = readw(0x1f8c) & 0x1ff;
int16 angle2 = readw(0x1f8f) & 0x1ff;
int32 tan1 = Tan(angle1);
int32 tan2 = Tan(angle2);
int16 y = readw(0x1f83) - readw(0x1f89);
int16 left, right;
for(int32 j = 0; j < 225; j++, y++) {
if(y >= 0) {
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
if(left < 0 && right < 0) {
left = 1;
right = 0;
} else if(left < 0) {
left = 0;
} else if(right < 0) {
right = 0;
}
if(left > 255 && right > 255) {
left = 255;
right = 254;
} else if(left > 255) {
left = 255;
} else if(right > 255) {
right = 255;
}
} else {
left = 1;
right = 0;
}
ram[j + 0x800] = (uint8)left;
ram[j + 0x900] = (uint8)right;
}
}
//Multiply
void Cx4::op25() {
r0 = ldr(0);
r1 = ldr(1);
mul(r0, r1, r0, r1);
str(0, r0);
str(1, r1);
}
//Transform Coords
void Cx4::op2d() {
C4WFXVal = readw(0x1f81);
C4WFYVal = readw(0x1f84);
C4WFZVal = readw(0x1f87);
C4WFX2Val = read (0x1f89);
C4WFY2Val = read (0x1f8a);
C4WFDist = read (0x1f8b);
C4WFScale = readw(0x1f90);
C4TransfWireFrame2();
writew(0x1f80, C4WFXVal);
writew(0x1f83, C4WFYVal);
}
//Sum
void Cx4::op40() {
r0 = 0;
for(uint32 i=0;i<0x800;i++) {
r0 += ram[i];
}
str(0, r0);
}
//Square
void Cx4::op54() {
r0 = ldr(0);
mul(r0, r0, r1, r2);
str(1, r1);
str(2, r2);
}
//Immediate Register
void Cx4::op5c() {
str(0, 0x000000);
immediate_reg(0);
}
//Immediate Register (Multiple)
void Cx4::op5e() { immediate_reg( 0); }
void Cx4::op60() { immediate_reg( 3); }
void Cx4::op62() { immediate_reg( 6); }
void Cx4::op64() { immediate_reg( 9); }
void Cx4::op66() { immediate_reg(12); }
void Cx4::op68() { immediate_reg(15); }
void Cx4::op6a() { immediate_reg(18); }
void Cx4::op6c() { immediate_reg(21); }
void Cx4::op6e() { immediate_reg(24); }
void Cx4::op70() { immediate_reg(27); }
void Cx4::op72() { immediate_reg(30); }
void Cx4::op74() { immediate_reg(33); }
void Cx4::op76() { immediate_reg(36); }
void Cx4::op78() { immediate_reg(39); }
void Cx4::op7a() { immediate_reg(42); }
void Cx4::op7c() { immediate_reg(45); }
//Immediate ROM
void Cx4::op89() {
str(0, 0x054336);
str(1, 0xffffff);
}
#endif

View File

@@ -1,59 +1,63 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#define DSP1_CPP
#include "dsp1.hpp"
#include "dsp1emu.cpp"
void DSP1::init() {}
void DSP1::enable() {}
void DSP1::power() {
reset();
}
void DSP1::reset() {
dsp1.reset();
}
/*****
* addr_decode()
* determine whether address is accessing
* data register (DR) or status register (SR)
* -- 0 (false) = DR
* -- 1 (true ) = SR
*
* note: there is no need to bounds check addresses,
* as memory mapper will not allow DSP1 accesses outside
* of expected ranges
*****/
bool DSP1::addr_decode(uint16 addr) {
switch(cartridge.dsp1_mapper()) {
case Cartridge::DSP1LoROM1MB: {
//$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR
return (addr >= 0xc000);
}
case Cartridge::DSP1LoROM2MB: {
//$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR
return (addr >= 0x4000);
}
case Cartridge::DSP1HiROM: {
//$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR
return (addr >= 0x7000);
}
}
return 0;
}
uint8 DSP1::read(unsigned addr) {
return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr();
}
void DSP1::write(unsigned addr, uint8 data) {
if(addr_decode(addr) == 0) {
dsp1.setDr(data);
}
}
#include <../base.hpp>
#define DSP1_CPP
namespace SNES {
DSP1 dsp1;
#include "dsp1emu.cpp"
void DSP1::init() {}
void DSP1::enable() {}
void DSP1::power() {
reset();
}
void DSP1::reset() {
dsp1.reset();
}
/*****
* addr_decode()
* determine whether address is accessing
* data register (DR) or status register (SR)
* -- 0 (false) = DR
* -- 1 (true ) = SR
*
* note: there is no need to bounds check addresses,
* as memory mapper will not allow DSP1 accesses outside
* of expected ranges
*****/
bool DSP1::addr_decode(uint16 addr) {
switch(cartridge.dsp1_mapper()) {
case Cartridge::DSP1LoROM1MB: {
//$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR
return (addr >= 0xc000);
}
case Cartridge::DSP1LoROM2MB: {
//$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR
return (addr >= 0x4000);
}
case Cartridge::DSP1HiROM: {
//$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR
return (addr >= 0x7000);
}
}
return 0;
}
uint8 DSP1::read(unsigned addr) {
return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr();
}
void DSP1::write(unsigned addr, uint8 data) {
if(addr_decode(addr) == 0) {
dsp1.setDr(data);
}
}
};

View File

@@ -1,18 +1,18 @@
#include "dsp1emu.hpp"
class DSP1 : public Memory {
private:
Dsp1 dsp1;
bool addr_decode(uint16 addr);
public:
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP1 dsp1;
#include "dsp1emu.hpp"
class DSP1 : public Memory {
private:
Dsp1 dsp1;
bool addr_decode(uint16 addr);
public:
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP1 dsp1;

File diff suppressed because it is too large Load Diff

View File

@@ -1,127 +1,127 @@
// DSP-1's emulation code
//
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
// Date: June 2006
#ifndef __DSP1EMUL_H
#define __DSP1EMUL_H
#define DSP1_VERSION 0x0102
class Dsp1
{
public:
// The DSP-1 status register has 16 bits, but only
// the upper 8 bits can be accessed from an external device, so all these
// positions are referred to the upper byte (bits D8 to D15)
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
// According to Overload's docs, these are the meanings of the flags:
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
// 0: Data transfer to and from the DSP-1 is 16 bits.
// 1: Data transfer to and from the DSP-1 is 8 bits.
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
// 0: Data transfer has terminated.
// 1: Data transfer in progress.
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
// 0: Internal Data Register Transfer.
// 1: External Data Register Transfer.
Dsp1();
uint8 getSr(); // return the status register's high byte
uint8 getDr();
void setDr(uint8 iDr);
void reset();
private:
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
struct Command {
void (Dsp1::*callback)(int16 *, int16 *);
unsigned int reads;
unsigned int writes;
};
static const Command mCommandTable[];
static const int16 MaxAZS_Exp[16];
static const int16 SinTable[];
static const int16 MulTable[];
static const uint16 DataRom[];
struct SharedData { // some RAM variables shared between commands
int16 MatrixA[3][3]; // attitude matrix A
int16 MatrixB[3][3];
int16 MatrixC[3][3];
int16 CentreX, CentreY, CentreZ; // center of projection
int16 CentreZ_C, CentreZ_E;
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
int16 Les, C_Les, E_Les;
int16 SinAas, CosAas;
int16 SinAzs, CosAzs;
int16 SinAZS, CosAZS;
int16 SecAZS_C1, SecAZS_E1;
int16 SecAZS_C2, SecAZS_E2;
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
} shared;
uint8 mSr; // status register
int mSrLowByteAccess;
uint16 mDr; // "internal" representation of the data register
FsmMajorState mFsmMajorState; // current major state of the FSM
uint8 mCommand; // current command processed by the FSM
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
int16 mReadBuffer[MAX_READS];
int16 mWriteBuffer[MAX_WRITES];
bool mFreeze; // need explanation? ;)
void fsmStep(bool read, uint8 &data); // FSM logic
// commands
void memoryTest(int16 *input, int16 *output);
void memoryDump(int16 *input, int16 *output);
void memorySize(int16 *input, int16 *output);
void multiply(int16* input, int16* output);
void multiply2(int16* input, int16* output);
void inverse(int16 *input, int16 *output);
void triangle(int16 *input, int16 *output);
void radius(int16 *input, int16 *output);
void range(int16 *input, int16 *output);
void range2(int16 *input, int16 *output);
void distance(int16 *input, int16 *output);
void rotate(int16 *input, int16 *output);
void polar(int16 *input, int16 *output);
void attitudeA(int16 *input, int16 *output);
void attitudeB(int16 *input, int16 *output);
void attitudeC(int16 *input, int16 *output);
void objectiveA(int16 *input, int16 *output);
void objectiveB(int16 *input, int16 *output);
void objectiveC(int16 *input, int16 *output);
void subjectiveA(int16 *input, int16 *output);
void subjectiveB(int16 *input, int16 *output);
void subjectiveC(int16 *input, int16 *output);
void scalarA(int16 *input, int16 *output);
void scalarB(int16 *input, int16 *output);
void scalarC(int16 *input, int16 *output);
void gyrate(int16 *input, int16 *output);
void parameter(int16 *input, int16 *output);
void raster(int16 *input, int16 *output);
void target(int16 *input, int16 *output);
void project(int16 *input, int16 *output);
// auxiliar functions
int16 sin(int16 Angle);
int16 cos(int16 Angle);
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
int16 denormalizeAndClip(int16 C, int16 E);
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
int16 shiftR(int16 C, int16 E);
};
#endif
// DSP-1's emulation code
//
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
// Date: June 2006
#ifndef __DSP1EMUL_H
#define __DSP1EMUL_H
#define DSP1_VERSION 0x0102
class Dsp1
{
public:
// The DSP-1 status register has 16 bits, but only
// the upper 8 bits can be accessed from an external device, so all these
// positions are referred to the upper byte (bits D8 to D15)
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
// According to Overload's docs, these are the meanings of the flags:
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
// 0: Data transfer to and from the DSP-1 is 16 bits.
// 1: Data transfer to and from the DSP-1 is 8 bits.
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
// 0: Data transfer has terminated.
// 1: Data transfer in progress.
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
// 0: Internal Data Register Transfer.
// 1: External Data Register Transfer.
Dsp1();
uint8 getSr(); // return the status register's high byte
uint8 getDr();
void setDr(uint8 iDr);
void reset();
private:
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
struct Command {
void (Dsp1::*callback)(int16 *, int16 *);
unsigned int reads;
unsigned int writes;
};
static const Command mCommandTable[];
static const int16 MaxAZS_Exp[16];
static const int16 SinTable[];
static const int16 MulTable[];
static const uint16 DataRom[];
struct SharedData { // some RAM variables shared between commands
int16 MatrixA[3][3]; // attitude matrix A
int16 MatrixB[3][3];
int16 MatrixC[3][3];
int16 CentreX, CentreY, CentreZ; // center of projection
int16 CentreZ_C, CentreZ_E;
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
int16 Les, C_Les, E_Les;
int16 SinAas, CosAas;
int16 SinAzs, CosAzs;
int16 SinAZS, CosAZS;
int16 SecAZS_C1, SecAZS_E1;
int16 SecAZS_C2, SecAZS_E2;
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
} shared;
uint8 mSr; // status register
int mSrLowByteAccess;
uint16 mDr; // "internal" representation of the data register
FsmMajorState mFsmMajorState; // current major state of the FSM
uint8 mCommand; // current command processed by the FSM
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
int16 mReadBuffer[MAX_READS];
int16 mWriteBuffer[MAX_WRITES];
bool mFreeze; // need explanation? ;)
void fsmStep(bool read, uint8 &data); // FSM logic
// commands
void memoryTest(int16 *input, int16 *output);
void memoryDump(int16 *input, int16 *output);
void memorySize(int16 *input, int16 *output);
void multiply(int16* input, int16* output);
void multiply2(int16* input, int16* output);
void inverse(int16 *input, int16 *output);
void triangle(int16 *input, int16 *output);
void radius(int16 *input, int16 *output);
void range(int16 *input, int16 *output);
void range2(int16 *input, int16 *output);
void distance(int16 *input, int16 *output);
void rotate(int16 *input, int16 *output);
void polar(int16 *input, int16 *output);
void attitudeA(int16 *input, int16 *output);
void attitudeB(int16 *input, int16 *output);
void attitudeC(int16 *input, int16 *output);
void objectiveA(int16 *input, int16 *output);
void objectiveB(int16 *input, int16 *output);
void objectiveC(int16 *input, int16 *output);
void subjectiveA(int16 *input, int16 *output);
void subjectiveB(int16 *input, int16 *output);
void subjectiveC(int16 *input, int16 *output);
void scalarA(int16 *input, int16 *output);
void scalarB(int16 *input, int16 *output);
void scalarC(int16 *input, int16 *output);
void gyrate(int16 *input, int16 *output);
void parameter(int16 *input, int16 *output);
void raster(int16 *input, int16 *output);
void target(int16 *input, int16 *output);
void project(int16 *input, int16 *output);
// auxiliar functions
int16 sin(int16 Angle);
int16 cos(int16 Angle);
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
int16 denormalizeAndClip(int16 C, int16 E);
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
int16 shiftR(int16 C, int16 E);
};
#endif

View File

@@ -1,136 +1,141 @@
#include <../base.hpp>
#define DSP2_CPP
#include "dsp2.hpp"
#include "dsp2_op.cpp"
void DSP2::init() {}
void DSP2::enable() {}
void DSP2::power() {
reset();
}
void DSP2::reset() {
status.waiting_for_command = true;
status.in_count = 0;
status.in_index = 0;
status.out_count = 0;
status.out_index = 0;
status.op05transparent = 0;
status.op05haslen = false;
status.op05len = 0;
status.op06haslen = false;
status.op06len = 0;
status.op09word1 = 0;
status.op09word2 = 0;
status.op0dhaslen = false;
status.op0doutlen = 0;
status.op0dinlen = 0;
}
uint8 DSP2::read(unsigned addr) {
uint8 r = 0xff;
if(status.out_count) {
r = status.output[status.out_index++];
status.out_index &= 511;
if(status.out_count == status.out_index) {
status.out_count = 0;
}
}
return r;
}
void DSP2::write(unsigned addr, uint8 data) {
if(status.waiting_for_command) {
status.command = data;
status.in_index = 0;
status.waiting_for_command = false;
switch(data) {
case 0x01: status.in_count = 32; break;
case 0x03: status.in_count = 1; break;
case 0x05: status.in_count = 1; break;
case 0x06: status.in_count = 1; break;
case 0x07: break;
case 0x08: break;
case 0x09: status.in_count = 4; break;
case 0x0d: status.in_count = 2; break;
case 0x0f: status.in_count = 0; break;
}
} else {
status.parameters[status.in_index++] = data;
status.in_index &= 511;
}
if(status.in_count == status.in_index) {
status.waiting_for_command = true;
status.out_index = 0;
switch(status.command) {
case 0x01: {
status.out_count = 32;
op01();
} break;
case 0x03: {
op03();
} break;
case 0x05: {
if(status.op05haslen) {
status.op05haslen = false;
status.out_count = status.op05len;
op05();
} else {
status.op05len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op05len * 2;
status.op05haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x06: {
if(status.op06haslen) {
status.op06haslen = false;
status.out_count = status.op06len;
op06();
} else {
status.op06len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op06len;
status.op06haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x07: break;
case 0x08: break;
case 0x09: {
op09();
} break;
case 0x0d: {
if(status.op0dhaslen) {
status.op0dhaslen = false;
status.out_count = status.op0doutlen;
op0d();
} else {
status.op0dinlen = status.parameters[0];
status.op0doutlen = status.parameters[1];
status.in_index = 0;
status.in_count = (status.op0dinlen + 1) >> 1;
status.op0dhaslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x0f: break;
}
}
}
DSP2::DSP2() {}
DSP2::~DSP2() {}
#define DSP2_CPP
namespace SNES {
DSP2 dsp2;
#include "dsp2_op.cpp"
void DSP2::init() {}
void DSP2::enable() {}
void DSP2::power() {
reset();
}
void DSP2::reset() {
status.waiting_for_command = true;
status.in_count = 0;
status.in_index = 0;
status.out_count = 0;
status.out_index = 0;
status.op05transparent = 0;
status.op05haslen = false;
status.op05len = 0;
status.op06haslen = false;
status.op06len = 0;
status.op09word1 = 0;
status.op09word2 = 0;
status.op0dhaslen = false;
status.op0doutlen = 0;
status.op0dinlen = 0;
}
uint8 DSP2::read(unsigned addr) {
uint8 r = 0xff;
if(status.out_count) {
r = status.output[status.out_index++];
status.out_index &= 511;
if(status.out_count == status.out_index) {
status.out_count = 0;
}
}
return r;
}
void DSP2::write(unsigned addr, uint8 data) {
if(status.waiting_for_command) {
status.command = data;
status.in_index = 0;
status.waiting_for_command = false;
switch(data) {
case 0x01: status.in_count = 32; break;
case 0x03: status.in_count = 1; break;
case 0x05: status.in_count = 1; break;
case 0x06: status.in_count = 1; break;
case 0x07: break;
case 0x08: break;
case 0x09: status.in_count = 4; break;
case 0x0d: status.in_count = 2; break;
case 0x0f: status.in_count = 0; break;
}
} else {
status.parameters[status.in_index++] = data;
status.in_index &= 511;
}
if(status.in_count == status.in_index) {
status.waiting_for_command = true;
status.out_index = 0;
switch(status.command) {
case 0x01: {
status.out_count = 32;
op01();
} break;
case 0x03: {
op03();
} break;
case 0x05: {
if(status.op05haslen) {
status.op05haslen = false;
status.out_count = status.op05len;
op05();
} else {
status.op05len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op05len * 2;
status.op05haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x06: {
if(status.op06haslen) {
status.op06haslen = false;
status.out_count = status.op06len;
op06();
} else {
status.op06len = status.parameters[0];
status.in_index = 0;
status.in_count = status.op06len;
status.op06haslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x07: break;
case 0x08: break;
case 0x09: {
op09();
} break;
case 0x0d: {
if(status.op0dhaslen) {
status.op0dhaslen = false;
status.out_count = status.op0doutlen;
op0d();
} else {
status.op0dinlen = status.parameters[0];
status.op0doutlen = status.parameters[1];
status.in_index = 0;
status.in_count = (status.op0dinlen + 1) >> 1;
status.op0dhaslen = true;
if(data)status.waiting_for_command = false;
}
} break;
case 0x0f: break;
}
}
}
DSP2::DSP2() {}
DSP2::~DSP2() {}
};

View File

@@ -1,44 +1,44 @@
class DSP2 : public Memory {
public:
struct {
bool waiting_for_command;
unsigned command;
unsigned in_count, in_index;
unsigned out_count, out_index;
uint8 parameters[512];
uint8 output[512];
uint8 op05transparent;
bool op05haslen;
int op05len;
bool op06haslen;
int op06len;
uint16 op09word1;
uint16 op09word2;
bool op0dhaslen;
int op0doutlen;
int op0dinlen;
} status;
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
DSP2();
~DSP2();
protected:
void op01();
void op03();
void op05();
void op06();
void op09();
void op0d();
};
extern DSP2 dsp2;
class DSP2 : public Memory {
public:
struct {
bool waiting_for_command;
unsigned command;
unsigned in_count, in_index;
unsigned out_count, out_index;
uint8 parameters[512];
uint8 output[512];
uint8 op05transparent;
bool op05haslen;
int op05len;
bool op06haslen;
int op06len;
uint16 op09word1;
uint16 op09word2;
bool op0dhaslen;
int op0doutlen;
int op0dinlen;
} status;
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
DSP2();
~DSP2();
protected:
void op01();
void op03();
void op05();
void op06();
void op09();
void op0d();
};
extern DSP2 dsp2;

View File

@@ -1,177 +1,177 @@
#ifdef DSP2_CPP
//convert bitmap to bitplane tile
void DSP2::op01() {
//op01 size is always 32 bytes input and output
//the hardware does strange things if you vary the size
unsigned char c0, c1, c2, c3;
unsigned char *p1 = status.parameters;
unsigned char *p2a = status.output;
unsigned char *p2b = status.output + 16; //halfway
//process 8 blocks of 4 bytes each
for(int j = 0; j < 8; j++) {
c0 = *p1++;
c1 = *p1++;
c2 = *p1++;
c3 = *p1++;
*p2a++ = (c0 & 0x10) << 3 |
(c0 & 0x01) << 6 |
(c1 & 0x10) << 1 |
(c1 & 0x01) << 4 |
(c2 & 0x10) >> 1 |
(c2 & 0x01) << 2 |
(c3 & 0x10) >> 3 |
(c3 & 0x01);
*p2a++ = (c0 & 0x20) << 2 |
(c0 & 0x02) << 5 |
(c1 & 0x20) |
(c1 & 0x02) << 3 |
(c2 & 0x20) >> 2 |
(c2 & 0x02) << 1 |
(c3 & 0x20) >> 4 |
(c3 & 0x02) >> 1;
*p2b++ = (c0 & 0x40) << 1 |
(c0 & 0x04) << 4 |
(c1 & 0x40) >> 1 |
(c1 & 0x04) << 2 |
(c2 & 0x40) >> 3 |
(c2 & 0x04) |
(c3 & 0x40) >> 5 |
(c3 & 0x04) >> 2;
*p2b++ = (c0 & 0x80) |
(c0 & 0x08) << 3 |
(c1 & 0x80) >> 2 |
(c1 & 0x08) << 1 |
(c2 & 0x80) >> 4 |
(c2 & 0x08) >> 1 |
(c3 & 0x80) >> 6 |
(c3 & 0x08) >> 3;
}
}
//set transparent color
void DSP2::op03() {
status.op05transparent = status.parameters[0];
}
//replace bitmap using transparent color
void DSP2::op05() {
uint8 color;
// Overlay bitmap with transparency.
// Input:
//
// Bitmap 1: i[0] <=> i[size-1]
// Bitmap 2: i[size] <=> i[2*size-1]
//
// Output:
//
// Bitmap 3: o[0] <=> o[size-1]
//
// Processing:
//
// Process all 4-bit pixels (nibbles) in the bitmap
//
// if ( BM2_pixel == transparent_color )
// pixelout = BM1_pixel
// else
// pixelout = BM2_pixel
// The max size bitmap is limited to 255 because the size parameter is a byte
// I think size=0 is an error. The behavior of the chip on size=0 is to
// return the last value written to DR if you read DR on Op05 with
// size = 0. I don't think it's worth implementing this quirk unless it's
// proven necessary.
unsigned char c1, c2;
unsigned char *p1 = status.parameters;
unsigned char *p2 = status.parameters + status.op05len;
unsigned char *p3 = status.output;
color = status.op05transparent & 0x0f;
for(int n = 0; n < status.op05len; n++) {
c1 = *p1++;
c2 = *p2++;
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
}
}
//reverse bitmap
void DSP2::op06() {
// Input:
// size
// bitmap
int i, j;
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
}
}
//multiply
void DSP2::op09() {
status.out_count = 4;
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
uint32 r;
r = status.op09word1 * status.op09word2;
status.output[0] = r;
status.output[1] = r >> 8;
status.output[2] = r >> 16;
status.output[3] = r >> 24;
}
//scale bitmap
void DSP2::op0d() {
// Bit accurate hardware algorithm - uses fixed point math
// This should match the DSP2 Op0D output exactly
// I wouldn't recommend using this unless you're doing hardware debug.
// In some situations it has small visual artifacts that
// are not readily apparent on a TV screen but show up clearly
// on a monitor. Use Overload's scaling instead.
// This is for hardware verification testing.
//
// One note: the HW can do odd byte scaling but since we divide
// by two to get the count of bytes this won't work well for
// odd byte scaling (in any of the current algorithm implementations).
// So far I haven't seen Dungeon Master use it.
// If it does we can adjust the parameters and code to work with it
uint32 multiplier; // Any size int >= 32-bits
uint32 pixloc; // match size of multiplier
int i, j;
uint8 pixelarray[512];
if(status.op0dinlen <= status.op0doutlen) {
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
} else {
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
}
pixloc = 0;
for(i = 0; i < status.op0doutlen * 2; i++) {
j = pixloc >> 16;
if(j & 1) {
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
} else {
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
}
pixloc += multiplier;
}
for(i = 0; i < status.op0doutlen; i++) {
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
}
}
//convert bitmap to bitplane tile
void DSP2::op01() {
//op01 size is always 32 bytes input and output
//the hardware does strange things if you vary the size
#endif
unsigned char c0, c1, c2, c3;
unsigned char *p1 = status.parameters;
unsigned char *p2a = status.output;
unsigned char *p2b = status.output + 16; //halfway
//process 8 blocks of 4 bytes each
for(int j = 0; j < 8; j++) {
c0 = *p1++;
c1 = *p1++;
c2 = *p1++;
c3 = *p1++;
*p2a++ = (c0 & 0x10) << 3 |
(c0 & 0x01) << 6 |
(c1 & 0x10) << 1 |
(c1 & 0x01) << 4 |
(c2 & 0x10) >> 1 |
(c2 & 0x01) << 2 |
(c3 & 0x10) >> 3 |
(c3 & 0x01);
*p2a++ = (c0 & 0x20) << 2 |
(c0 & 0x02) << 5 |
(c1 & 0x20) |
(c1 & 0x02) << 3 |
(c2 & 0x20) >> 2 |
(c2 & 0x02) << 1 |
(c3 & 0x20) >> 4 |
(c3 & 0x02) >> 1;
*p2b++ = (c0 & 0x40) << 1 |
(c0 & 0x04) << 4 |
(c1 & 0x40) >> 1 |
(c1 & 0x04) << 2 |
(c2 & 0x40) >> 3 |
(c2 & 0x04) |
(c3 & 0x40) >> 5 |
(c3 & 0x04) >> 2;
*p2b++ = (c0 & 0x80) |
(c0 & 0x08) << 3 |
(c1 & 0x80) >> 2 |
(c1 & 0x08) << 1 |
(c2 & 0x80) >> 4 |
(c2 & 0x08) >> 1 |
(c3 & 0x80) >> 6 |
(c3 & 0x08) >> 3;
}
}
//set transparent color
void DSP2::op03() {
status.op05transparent = status.parameters[0];
}
//replace bitmap using transparent color
void DSP2::op05() {
uint8 color;
// Overlay bitmap with transparency.
// Input:
//
// Bitmap 1: i[0] <=> i[size-1]
// Bitmap 2: i[size] <=> i[2*size-1]
//
// Output:
//
// Bitmap 3: o[0] <=> o[size-1]
//
// Processing:
//
// Process all 4-bit pixels (nibbles) in the bitmap
//
// if ( BM2_pixel == transparent_color )
// pixelout = BM1_pixel
// else
// pixelout = BM2_pixel
// The max size bitmap is limited to 255 because the size parameter is a byte
// I think size=0 is an error. The behavior of the chip on size=0 is to
// return the last value written to DR if you read DR on Op05 with
// size = 0. I don't think it's worth implementing this quirk unless it's
// proven necessary.
unsigned char c1, c2;
unsigned char *p1 = status.parameters;
unsigned char *p2 = status.parameters + status.op05len;
unsigned char *p3 = status.output;
color = status.op05transparent & 0x0f;
for(int n = 0; n < status.op05len; n++) {
c1 = *p1++;
c2 = *p2++;
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
}
}
//reverse bitmap
void DSP2::op06() {
// Input:
// size
// bitmap
int i, j;
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
}
}
//multiply
void DSP2::op09() {
status.out_count = 4;
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
uint32 r;
r = status.op09word1 * status.op09word2;
status.output[0] = r;
status.output[1] = r >> 8;
status.output[2] = r >> 16;
status.output[3] = r >> 24;
}
//scale bitmap
void DSP2::op0d() {
// Bit accurate hardware algorithm - uses fixed point math
// This should match the DSP2 Op0D output exactly
// I wouldn't recommend using this unless you're doing hardware debug.
// In some situations it has small visual artifacts that
// are not readily apparent on a TV screen but show up clearly
// on a monitor. Use Overload's scaling instead.
// This is for hardware verification testing.
//
// One note: the HW can do odd byte scaling but since we divide
// by two to get the count of bytes this won't work well for
// odd byte scaling (in any of the current algorithm implementations).
// So far I haven't seen Dungeon Master use it.
// If it does we can adjust the parameters and code to work with it
uint32 multiplier; // Any size int >= 32-bits
uint32 pixloc; // match size of multiplier
int i, j;
uint8 pixelarray[512];
if(status.op0dinlen <= status.op0doutlen) {
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
} else {
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
}
pixloc = 0;
for(i = 0; i < status.op0doutlen * 2; i++) {
j = pixloc >> 16;
if(j & 1) {
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
} else {
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
}
pixloc += multiplier;
}
for(i = 0; i < status.op0doutlen; i++) {
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
}
}
#endif

View File

@@ -1,35 +1,40 @@
#include <../base.hpp>
#define DSP3_CPP
#include "dsp3.hpp"
namespace DSP3i {
#define bool8 uint8
#include "dsp3emu.c"
#undef bool8
};
void DSP3::init() {
}
void DSP3::enable() {
}
void DSP3::power() {
reset();
}
void DSP3::reset() {
DSP3i::DSP3_Reset();
}
uint8 DSP3::read(unsigned addr) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(unsigned addr, uint8 data) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}
#define DSP3_CPP
namespace SNES {
DSP3 dsp3;
namespace DSP3i {
#define bool8 uint8
#include "dsp3emu.c"
#undef bool8
};
void DSP3::init() {
}
void DSP3::enable() {
}
void DSP3::power() {
reset();
}
void DSP3::reset() {
DSP3i::DSP3_Reset();
}
uint8 DSP3::read(unsigned addr) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(unsigned addr, uint8 data) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}
};

View File

@@ -1,12 +1,12 @@
class DSP3 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP3 dsp3;
class DSP3 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP3 dsp3;

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +1,60 @@
#include <../base.hpp>
#define DSP4_CPP
#include "dsp4.hpp"
namespace DSP4i {
inline uint16 READ_WORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8);
}
inline uint32 READ_DWORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
}
inline void WRITE_WORD(uint8 *addr, uint16 data) {
addr[0] = data;
addr[1] = data >> 8;
}
#define bool8 uint8
#include "dsp4emu.c"
#undef bool8
};
void DSP4::init() {
}
void DSP4::enable() {
}
void DSP4::power() {
reset();
}
void DSP4::reset() {
DSP4i::InitDSP4();
}
uint8 DSP4::read(unsigned addr) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::DSP4GetByte();
return DSP4i::dsp4_byte;
}
return 0x80;
}
void DSP4::write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::dsp4_byte = data;
DSP4i::DSP4SetByte();
}
}
#define DSP4_CPP
namespace SNES {
DSP4 dsp4;
namespace DSP4i {
inline uint16 READ_WORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8);
}
inline uint32 READ_DWORD(uint8 *addr) {
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
}
inline void WRITE_WORD(uint8 *addr, uint16 data) {
addr[0] = data;
addr[1] = data >> 8;
}
#define bool8 uint8
#include "dsp4emu.c"
#undef bool8
};
void DSP4::init() {
}
void DSP4::enable() {
}
void DSP4::power() {
reset();
}
void DSP4::reset() {
DSP4i::InitDSP4();
}
uint8 DSP4::read(unsigned addr) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::DSP4GetByte();
return DSP4i::dsp4_byte;
}
return 0x80;
}
void DSP4::write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr < 0xc000) {
DSP4i::dsp4_address = addr;
DSP4i::dsp4_byte = data;
DSP4i::DSP4SetByte();
}
}
};

View File

@@ -1,12 +1,12 @@
class DSP4 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP4 dsp4;
class DSP4 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern DSP4 dsp4;

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +1,108 @@
//DSP-4 emulator code
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
#ifndef DSP4EMU_H
#define DSP4EMU_H
#undef TRUE
#undef FALSE
#define TRUE true
#define FALSE false
struct DSP4_t
{
bool8 waiting4command;
bool8 half_command;
uint16 command;
uint32 in_count;
uint32 in_index;
uint32 out_count;
uint32 out_index;
uint8 parameters[512];
uint8 output[512];
};
extern struct DSP4_t DSP4;
struct DSP4_vars_t
{
// op control
int8 DSP4_Logic; // controls op flow
// projection format
int16 lcv; // loop-control variable
int16 distance; // z-position into virtual world
int16 raster; // current raster line
int16 segments; // number of raster lines drawn
// 1.15.16 or 1.15.0 [sign, integer, fraction]
int32 world_x; // line of x-projection in world
int32 world_y; // line of y-projection in world
int32 world_dx; // projection line x-delta
int32 world_dy; // projection line y-delta
int16 world_ddx; // x-delta increment
int16 world_ddy; // y-delta increment
int32 world_xenv; // world x-shaping factor
int16 world_yofs; // world y-vertical scroll
int16 view_x1; // current viewer-x
int16 view_y1; // current viewer-y
int16 view_x2; // future viewer-x
int16 view_y2; // future viewer-y
int16 view_dx; // view x-delta factor
int16 view_dy; // view y-delta factor
int16 view_xofs1; // current viewer x-vertical scroll
int16 view_yofs1; // current viewer y-vertical scroll
int16 view_xofs2; // future viewer x-vertical scroll
int16 view_yofs2; // future viewer y-vertical scroll
int16 view_yofsenv; // y-scroll shaping factor
int16 view_turnoff_x; // road turnoff data
int16 view_turnoff_dx; // road turnoff delta factor
// drawing area
int16 viewport_cx; // x-center of viewport window
int16 viewport_cy; // y-center of render window
int16 viewport_left; // x-left of viewport
int16 viewport_right; // x-right of viewport
int16 viewport_top; // y-top of viewport
int16 viewport_bottom; // y-bottom of viewport
// sprite structure
int16 sprite_x; // projected x-pos of sprite
int16 sprite_y; // projected y-pos of sprite
int16 sprite_attr; // obj attributes
bool8 sprite_size; // sprite size: 8x8 or 16x16
int16 sprite_clipy; // visible line to clip pixels off
int16 sprite_count;
// generic projection variables designed for
// two solid polygons + two polygon sides
int16 poly_clipLf[2][2]; // left clip boundary
int16 poly_clipRt[2][2]; // right clip boundary
int16 poly_ptr[2][2]; // HDMA structure pointers
int16 poly_raster[2][2]; // current raster line below horizon
int16 poly_top[2][2]; // top clip boundary
int16 poly_bottom[2][2]; // bottom clip boundary
int16 poly_cx[2][2]; // center for left/right points
int16 poly_start[2]; // current projection points
int16 poly_plane[2]; // previous z-plane distance
// OAM
int16 OAM_attr[16]; // OAM (size,MSB) data
int16 OAM_index; // index into OAM table
int16 OAM_bits; // offset into OAM table
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
int16 OAM_Row[32]; // current number of tiles per row
};
extern struct DSP4_vars_t DSP4_vars;
#endif
//DSP-4 emulator code
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
#ifndef DSP4EMU_H
#define DSP4EMU_H
#undef TRUE
#undef FALSE
#define TRUE true
#define FALSE false
struct DSP4_t
{
bool8 waiting4command;
bool8 half_command;
uint16 command;
uint32 in_count;
uint32 in_index;
uint32 out_count;
uint32 out_index;
uint8 parameters[512];
uint8 output[512];
};
extern struct DSP4_t DSP4;
struct DSP4_vars_t
{
// op control
int8 DSP4_Logic; // controls op flow
// projection format
int16 lcv; // loop-control variable
int16 distance; // z-position into virtual world
int16 raster; // current raster line
int16 segments; // number of raster lines drawn
// 1.15.16 or 1.15.0 [sign, integer, fraction]
int32 world_x; // line of x-projection in world
int32 world_y; // line of y-projection in world
int32 world_dx; // projection line x-delta
int32 world_dy; // projection line y-delta
int16 world_ddx; // x-delta increment
int16 world_ddy; // y-delta increment
int32 world_xenv; // world x-shaping factor
int16 world_yofs; // world y-vertical scroll
int16 view_x1; // current viewer-x
int16 view_y1; // current viewer-y
int16 view_x2; // future viewer-x
int16 view_y2; // future viewer-y
int16 view_dx; // view x-delta factor
int16 view_dy; // view y-delta factor
int16 view_xofs1; // current viewer x-vertical scroll
int16 view_yofs1; // current viewer y-vertical scroll
int16 view_xofs2; // future viewer x-vertical scroll
int16 view_yofs2; // future viewer y-vertical scroll
int16 view_yofsenv; // y-scroll shaping factor
int16 view_turnoff_x; // road turnoff data
int16 view_turnoff_dx; // road turnoff delta factor
// drawing area
int16 viewport_cx; // x-center of viewport window
int16 viewport_cy; // y-center of render window
int16 viewport_left; // x-left of viewport
int16 viewport_right; // x-right of viewport
int16 viewport_top; // y-top of viewport
int16 viewport_bottom; // y-bottom of viewport
// sprite structure
int16 sprite_x; // projected x-pos of sprite
int16 sprite_y; // projected y-pos of sprite
int16 sprite_attr; // obj attributes
bool8 sprite_size; // sprite size: 8x8 or 16x16
int16 sprite_clipy; // visible line to clip pixels off
int16 sprite_count;
// generic projection variables designed for
// two solid polygons + two polygon sides
int16 poly_clipLf[2][2]; // left clip boundary
int16 poly_clipRt[2][2]; // right clip boundary
int16 poly_ptr[2][2]; // HDMA structure pointers
int16 poly_raster[2][2]; // current raster line below horizon
int16 poly_top[2][2]; // top clip boundary
int16 poly_bottom[2][2]; // bottom clip boundary
int16 poly_cx[2][2]; // center for left/right points
int16 poly_start[2]; // current projection points
int16 poly_plane[2]; // previous z-plane distance
// OAM
int16 OAM_attr[16]; // OAM (size,MSB) data
int16 OAM_index; // index into OAM table
int16 OAM_bits; // offset into OAM table
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
int16 OAM_Row[32]; // current number of tiles per row
};
extern struct DSP4_vars_t DSP4_vars;
#endif

View File

@@ -1,72 +1,77 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#include "obc1.hpp"
void OBC1::init() {}
void OBC1::enable() {}
void OBC1::power() {
reset();
}
void OBC1::reset() {
for(unsigned i = 0x0000; i <= 0x1fff; i++) ram_write(i, 0xff);
status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00;
status.address = (ram_read(0x1ff6) & 0x7f);
status.shift = (ram_read(0x1ff6) & 3) << 1;
}
uint8 OBC1::read(unsigned addr) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_read(addr);
switch(addr) { default: //never used, avoids compiler warning
case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0);
case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1);
case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2);
case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3);
case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200);
case 0x1ff5: case 0x1ff6: case 0x1ff7: return ram_read(addr);
}
}
void OBC1::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_write(addr, data);
switch(addr) {
case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); break;
case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); break;
case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); break;
case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); break;
case 0x1ff4: {
uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
} break;
case 0x1ff5: {
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
ram_write(addr, data);
} break;
case 0x1ff6: {
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
ram_write(addr, data);
} break;
case 0x1ff7: {
ram_write(addr, data);
} break;
}
}
uint8 OBC1::ram_read(unsigned addr) {
return memory::cartram.read(addr & 0x1fff);
}
void OBC1::ram_write(unsigned addr, uint8 data) {
memory::cartram.write(addr & 0x1fff, data);
}
OBC1::OBC1() {}
OBC1::~OBC1() {}
#include <../base.hpp>
#define OBC1_CPP
namespace SNES {
OBC1 obc1;
void OBC1::init() {}
void OBC1::enable() {}
void OBC1::power() {
reset();
}
void OBC1::reset() {
for(unsigned i = 0x0000; i <= 0x1fff; i++) ram_write(i, 0xff);
status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00;
status.address = (ram_read(0x1ff6) & 0x7f);
status.shift = (ram_read(0x1ff6) & 3) << 1;
}
uint8 OBC1::read(unsigned addr) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_read(addr);
switch(addr) { default: //never used, avoids compiler warning
case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0);
case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1);
case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2);
case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3);
case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200);
case 0x1ff5: case 0x1ff6: case 0x1ff7: return ram_read(addr);
}
}
void OBC1::write(unsigned addr, uint8 data) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) return ram_write(addr, data);
switch(addr) {
case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); break;
case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); break;
case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); break;
case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); break;
case 0x1ff4: {
uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
} break;
case 0x1ff5: {
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
ram_write(addr, data);
} break;
case 0x1ff6: {
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
ram_write(addr, data);
} break;
case 0x1ff7: {
ram_write(addr, data);
} break;
}
}
uint8 OBC1::ram_read(unsigned addr) {
return memory::cartram.read(addr & 0x1fff);
}
void OBC1::ram_write(unsigned addr, uint8 data) {
memory::cartram.write(addr & 0x1fff, data);
}
OBC1::OBC1() {}
OBC1::~OBC1() {}
};

View File

@@ -1,25 +1,25 @@
class OBC1 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
OBC1();
~OBC1();
private:
uint8 ram_read(unsigned addr);
void ram_write(unsigned addr, uint8 data);
struct {
uint16 address;
uint16 baseptr;
uint16 shift;
} status;
};
extern OBC1 obc1;
class OBC1 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
OBC1();
~OBC1();
private:
uint8 ram_read(unsigned addr);
void ram_write(unsigned addr, uint8 data);
struct {
uint16 address;
uint16 baseptr;
uint16 shift;
} status;
};
extern OBC1 obc1;

View File

@@ -1,150 +1,121 @@
#ifdef SA1_CPP
namespace memory {
namespace cpu {
CPUIRAM iram;
CPUBWRAM bwram;
}
SA1Bus sa1bus;
namespace sa1 {
SA1IRAM iram;
SA1BWRAM bwram;
SA1BitmapRAM bitmapram;
}
namespace memory {
static VectorSelectionPage vectorsp;
static StaticRAM iram(2048);
static MappedRAM &bwram = memory::cartram;
static CC1BWRAM cc1bwram;
static BitmapRAM bitmapram;
}
void SA1Bus::init() {
for(uint32_t i = 0x0000; i <= 0xffff; i++) {
map(i << 8, memory::memory_unmapped, 0);
}
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
for(uint16_t i = 0x2200; i <= 0x23ff; i++) memory::mmio.map(i, sa1);
for(uint16_t i = 0x2200; i <= 0x23ff; i++) {
memory::mmio.map(i, sa1);
}
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::sa1::iram);
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1::iram);
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bwram);
map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bwram);
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1::bwram, 0, 0x040000);
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::sa1::bitmapram);
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1::iram);
map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::bwram);
map(MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
map(MapLinear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
map(MapDirect, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1::iram);
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bwram);
map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram);
map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
bus.map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::cpu::iram);
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cpu::bwram);
bus.map(MapLinear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram);
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::cartrom);
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cpu::bwram, 0, 0x040000);
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::cpu::iram);
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cpu::bwram);
bus.map(MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::cc1bwram);
bus.map(MapLinear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram);
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::cartrom);
bus.map(MapLinear, 0xc0, 0xff, 0x0000, 0xffff, memory::cartrom);
memory::vectorsp.sync();
}
//=======
//CPUIRAM
//=======
//===================
//VectorSelectionPage
//===================
unsigned CPUIRAM::size() const {
return sizeof(sa1.iram);
//this class maps $00:[ff00-ffff] for the purpose of supporting:
//$2209.d6 IVSW (S-CPU IRQ vector selection) (0 = cart, 1 = SA-1)
//$2209.d4 NVSW (S-CPU NMI vector selection) (0 = cart, 1 = SA-1)
//when set, vector addresses are over-ridden with SA-1 register settings:
//SIV = S-CPU IRQ vector address override
//SNV = S-CPU NMI vector address override
//
//$00:[ffea-ffeb|ffee-ffef] are special cased on read;
//all other addresses return original mapped data.
uint8_t VectorSelectionPage::read(unsigned addr) {
switch(0xff00 | (addr & 0xff)) {
case 0xffea: case 0xffeb: {
if(sa1.mmio.cpu_nvsw == true) return (sa1.mmio.snv >> ((addr & 1) << 3));
} break;
case 0xffee: case 0xffef: {
if(sa1.mmio.cpu_ivsw == true) return (sa1.mmio.siv >> ((addr & 1) << 3));
} break;
}
return access->read(addr);
}
uint8_t CPUIRAM::read(unsigned addr) {
return sa1.iram[addr];
void VectorSelectionPage::write(unsigned addr, uint8_t data) {
return access->write(addr, data);
}
void CPUIRAM::write(unsigned addr, uint8_t data) {
uint8_t wpbit = (addr >> 8) & 7;
if(1 || sa1.mmio.siwp & wpbit) {
//allow only when write-protection is disabled
sa1.iram[addr] = data;
//call this whenever bus is remapped.
//note: S-CPU and SA-1 bus always share $00:[ff00-ffff] as cartridge ROM data;
//the SA-1 MMC does not allow mapping these independently between processors.
//this allows this class to be shared for both, caching only ones' access class.
void VectorSelectionPage::sync() {
if(bus.page[0x00ff00 >> 8].access != this) {
//bus was re-mapped, hook access routine
access = bus.page[0x00ff00 >> 8].access;
bus.page[0x00ff00 >> 8].access = this;
sa1bus.page[0x00ff00 >> 8].access = this;
}
}
//========
//CPUBWRAM
//CC1BWRAM
//========
unsigned CPUBWRAM::size() const {
unsigned CC1BWRAM::size() const {
return memory::cartram.size();
}
uint8_t CPUBWRAM::read(unsigned addr) {
if(cc1dma) return sa1.dma_cc1_read(addr);
uint8_t CC1BWRAM::read(unsigned addr) {
if(dma) return sa1.dma_cc1_read(addr);
return memory::cartram.read(addr);
}
void CPUBWRAM::write(unsigned addr, uint8_t data) {
if(sa1.mmio.swen == false) {
//write-protection enabled
unsigned limit = 0x100 << sa1.mmio.bwp;
//if(addr < limit) return;
}
void CC1BWRAM::write(unsigned addr, uint8_t data) {
memory::cartram.write(addr, data);
}
//=======
//SA1IRAM
//=======
//=========
//BitmapRAM
//=========
unsigned SA1IRAM::size() const {
return sizeof(sa1.iram);
}
uint8_t SA1IRAM::read(unsigned addr) {
return sa1.iram[addr];
}
void SA1IRAM::write(unsigned addr, uint8_t data) {
uint8_t wpbit = (addr >> 8) & 7;
if(1 || sa1.mmio.ciwp & wpbit) {
//allow only when write-protection is disabled
sa1.iram[addr] = data;
}
}
//========
//SA1BWRAM
//========
unsigned SA1BWRAM::size() const {
return memory::cartram.size();
}
uint8_t SA1BWRAM::read(unsigned addr) {
return memory::cartram.read(addr);
}
void SA1BWRAM::write(unsigned addr, uint8_t data) {
if(sa1.mmio.cwen == false) {
//write-protection enabled
unsigned limit = 0x100 << sa1.mmio.bwp;
//if(addr < limit) return;
}
memory::cartram.write(addr, data);
}
//============
//SA1BitmapRAM
//============
unsigned SA1BitmapRAM::size() const {
unsigned BitmapRAM::size() const {
return 0x100000;
}
uint8_t SA1BitmapRAM::read(unsigned addr) {
uint8_t BitmapRAM::read(unsigned addr) {
if(sa1.mmio.bbf == 0) {
//4bpp
unsigned shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) {
switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 15;
case 1: return (memory::cartram.read(addr) >> 4) & 15;
}
@@ -152,7 +123,7 @@ uint8_t SA1BitmapRAM::read(unsigned addr) {
//2bpp
unsigned shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) {
switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 3;
case 1: return (memory::cartram.read(addr) >> 2) & 3;
case 2: return (memory::cartram.read(addr) >> 4) & 3;
@@ -161,12 +132,12 @@ uint8_t SA1BitmapRAM::read(unsigned addr) {
}
}
void SA1BitmapRAM::write(unsigned addr, uint8_t data) {
void BitmapRAM::write(unsigned addr, uint8_t data) {
if(sa1.mmio.bbf == 0) {
//4bpp
uint8_t shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) {
switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
}
@@ -174,7 +145,7 @@ void SA1BitmapRAM::write(unsigned addr, uint8_t data) {
//2bpp
uint8_t shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) {
switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;

View File

@@ -1,49 +1,23 @@
class SA1Bus : public Bus {
public:
struct SA1Bus : Bus {
void init();
};
struct CPUIRAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
struct VectorSelectionPage : Memory {
alwaysinline uint8_t read(unsigned);
alwaysinline void write(unsigned, uint8_t);
void sync();
Memory *access;
};
struct CPUBWRAM : Memory {
bool cc1dma;
struct CC1BWRAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
alwaysinline uint8_t read(unsigned);
alwaysinline void write(unsigned, uint8_t);
bool dma;
};
struct SA1IRAM : Memory {
struct BitmapRAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
alwaysinline uint8_t read(unsigned);
alwaysinline void write(unsigned, uint8_t);
};
struct SA1BWRAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SA1BitmapRAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
namespace memory {
namespace cpu {
extern CPUIRAM iram;
extern CPUBWRAM bwram;
}
namespace sa1 {
extern SA1IRAM iram;
extern SA1BWRAM bwram;
extern SA1BitmapRAM bitmapram;
}
}

View File

@@ -9,9 +9,8 @@ void SA1::dma_normal() {
uint8_t data = regs.mdr;
uint32_t dsa = mmio.dsa++;
uint32_t dda = mmio.dda++;
add_clocks(4);
scheduler.sync_copcpu();
//source and destination cannot be the same
if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestBWRAM) continue;
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue;
@@ -29,7 +28,7 @@ void SA1::dma_normal() {
} break;
case DMA::SourceIRAM: {
data = iram[dsa & 0x07ff];
data = memory::iram.read(dsa & 0x07ff);
} break;
}
@@ -41,25 +40,26 @@ void SA1::dma_normal() {
} break;
case DMA::DestIRAM: {
iram[dda & 0x07ff] = data;
memory::iram.write(dda & 0x07ff, data);
} break;
}
}
dma.mode = DMA::Inactive;
mmio.dma_irqfl = true;
if(mmio.dma_irqen) mmio.dma_irqcl = 0;
}
//((byte & 6) << 3) + (byte & 1) explanation:
//transforms a byte index (0-7) into a planar index:
//result[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
//works for 2bpp, 4bpp and 8bpp modes
//===========================
//type-1 character conversion
//===========================
void SA1::dma_cc1() {
memory::cpu::bwram.cc1dma = true;
dma.tile = 0;
dma.mode = DMA::Inactive;
memory::cc1bwram.dma = true;
mmio.chdma_irqfl = true;
if(mmio.chdma_irqen) {
mmio.chdma_irqcl = 0;
@@ -75,7 +75,7 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
//buffer next character to I-RAM
unsigned bpp = 2 << (2 - mmio.dmacb);
unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb;
unsigned bwmask = memory::sa1::bwram.size() - 1;
unsigned bwmask = memory::bwram.size() - 1;
unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
unsigned ty = (tile >> mmio.dmasize);
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
@@ -83,8 +83,8 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
for(unsigned y = 0; y < 8; y++) {
uint64_t data = 0;
for(unsigned n = 0; n < bpp; n++) {
data |= (uint64_t)memory::sa1::bwram.read((bwaddr + n) & bwmask) << (n << 3);
for(unsigned byte = 0; byte < bpp; byte++) {
data |= (uint64_t)memory::bwram.read((bwaddr + byte) & bwmask) << (byte << 3);
}
bwaddr += bpl;
@@ -102,15 +102,14 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
out[7] |= (data & 1) << (7 - x); data >>= 1;
}
for(unsigned n = 0; n < bpp; n++) {
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
unsigned p = mmio.dda + (y << 1) + index[n];
iram[p & 0x07ff] = out[n];
for(unsigned byte = 0; byte < bpp; byte++) {
unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1);
memory::iram.write(p & 0x07ff, out[byte]);
}
}
}
return iram[(mmio.dda + (addr & charmask)) & 0x07ff];
return memory::iram.read((mmio.dda + (addr & charmask)) & 0x07ff);
}
//===========================
@@ -118,7 +117,7 @@ uint8_t SA1::dma_cc1_read(unsigned addr) {
//===========================
void SA1::dma_cc2() {
//select register file index (0-7 or 8-F)
//select register file index (0-7 or 8-15)
const uint8_t *brf = &mmio.brf[(dma.line & 1) << 3];
unsigned bpp = 2 << (2 - mmio.dmacb);
unsigned addr = mmio.dda & 0x07ff;
@@ -131,14 +130,9 @@ void SA1::dma_cc2() {
for(unsigned bit = 0; bit < 8; bit++) {
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
}
static const unsigned index[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
iram[addr + index[byte]] = output;
add_clocks(4);
scheduler.sync_copcpu();
memory::iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
}
dma.mode = DMA::Inactive;
dma.line = (dma.line + 1) & 15;
}

View File

@@ -2,10 +2,6 @@ struct DMA {
enum CDEN { DmaNormal = 0, DmaCharConversion = 1 };
enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 };
enum DD { DestIRAM = 0, DestBWRAM = 1 };
enum Mode { Inactive, Normal, CC1, CC2 } mode;
unsigned clocks;
bool tile;
unsigned line;
} dma;

View File

@@ -5,55 +5,35 @@
//==========================
void SA1::op_io() {
add_clocks(2);
tick();
if(regs.wai) scheduler.sync_copcpu();
cycle_edge();
}
//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks)
//BW-RAM is accessed at ~5.37MHz (4 clock ticks)
//tick() == 2 clock ticks
//note: bus conflict delays are not emulated at this time
#define is_bwram(addr) (\
((addr & 0x40e000) == 0x006000) \
|| ((addr & 0xf00000) == 0x400000) \
|| ((addr & 0xf00000) == 0x600000) \
)
uint8_t SA1::op_read(unsigned addr) {
add_clocks(bus_speed(addr));
tick();
if(is_bwram(addr)) tick();
scheduler.sync_copcpu();
regs.mdr = sa1bus.read(addr);
cycle_edge();
return regs.mdr;
return sa1bus.read(addr);
}
void SA1::op_write(unsigned addr, uint8_t data) {
add_clocks(bus_speed(addr));
tick();
if(is_bwram(addr)) tick();
scheduler.sync_copcpu();
sa1bus.write(addr, regs.mdr = data);
cycle_edge();
sa1bus.write(addr, data);
}
void SA1::cycle_edge() {
switch(dma.mode) {
case DMA::Normal: dma_normal(); break;
case DMA::CC1: dma_cc1(); break;
case DMA::CC2: dma_cc2(); break;
}
}
//$[00-3f:80-bf]:[8000-ffff]
//$[c0-ff] :[0000-ffff]
#define ROM(n) ( \
((n & 0x408000) == 0x008000) \
|| ((n & 0xc00000) == 0xc00000) \
)
//$[00-3f|80-bf]:[0000-07ff]
//$[00-3f|80-bf]:[3000-37ff]
#define IRAM(n) ( \
((n & 0x40f800) == 0x000000) \
|| ((n & 0x40f800) == 0x003000) \
)
unsigned SA1::bus_speed(unsigned addr) {
if(IRAM(addr)) return 2;
if(ROM(addr)) return (ROM(cpu.regs.bus) ? 4 : 2);
return 4; //MMIO, BW-RAM
}
#undef ROM
#undef IRAM
#undef is_bwram
#endif

View File

@@ -1,5 +1,4 @@
void op_io();
uint8_t op_read(unsigned addr);
void op_write(unsigned addr, uint8_t data);
void cycle_edge();
unsigned bus_speed(unsigned addr);
alwaysinline void op_io();
alwaysinline uint8_t op_read(unsigned addr);
alwaysinline void op_write(unsigned addr, uint8_t data);
alwaysinline unsigned bus_speed(unsigned addr);

View File

@@ -1,5 +1,13 @@
#ifdef SA1_CPP
//BS-X flash carts, when present, are mapped to 0x400000+
Memory& SA1::mmio_access(unsigned &addr) {
if(!memory::bsxflash.data()) return memory::cartrom;
if(addr < 0x400000) return memory::cartrom;
addr &= 0x3fffff;
return bsxflash;
}
//(CCNT) SA-1 control
void SA1::mmio_w2200(uint8_t data) {
if(mmio.sa1_resb && !(data & 0x80)) {
@@ -86,17 +94,10 @@ void SA1::mmio_w2209(uint8_t data) {
//(CIE) SA-1 interrupt enable
void SA1::mmio_w220a(uint8_t data) {
if(!mmio.sa1_irqen && (data & 0x80)) {
if(mmio.sa1_irqfl) mmio.sa1_irqcl = 0;
}
if(!mmio.dma_irqen && (data & 0x20)) {
if(mmio.dma_irqfl) mmio.dma_irqcl = 0;
}
if(!mmio.sa1_nmien && (data & 0x10)) {
if(mmio.sa1_nmifl) mmio.sa1_nmicl = 0;
}
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0;
if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0;
if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0;
mmio.sa1_irqen = (data & 0x80);
mmio.timer_irqen = (data & 0x40);
@@ -111,17 +112,18 @@ void SA1::mmio_w220b(uint8_t data) {
mmio.dma_irqcl = (data & 0x20);
mmio.sa1_nmicl = (data & 0x10);
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
if(mmio.timer_irqcl) mmio.timer_irqfl = false;
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
}
//(SNV) S-CPU NMI vector
void SA1::mmio_w220c(uint8_t data) { mmio.snv = (mmio.snv & 0xff00) | data; }
void SA1::mmio_w220c(uint8_t data) { mmio.snv = (mmio.snv & 0xff00) | data; }
void SA1::mmio_w220d(uint8_t data) { mmio.snv = (data << 8) | (mmio.snv & 0xff); }
//(SIV) S-CPU IRQ vector
void SA1::mmio_w220e(uint8_t data) { mmio.siv = (mmio.siv & 0xff00) | data; }
void SA1::mmio_w220e(uint8_t data) { mmio.siv = (mmio.siv & 0xff00) | data; }
void SA1::mmio_w220f(uint8_t data) { mmio.siv = (data << 8) | (mmio.siv & 0xff); }
//(TMC) H/V timer control
@@ -150,10 +152,21 @@ void SA1::mmio_w2220(uint8_t data) {
mmio.cbmode = (data & 0x80);
mmio.cb = (data & 0x07);
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, (mmio.cbmode == 0) ? 0x000000 : (mmio.cb << 20));
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, memory::cartrom, mmio.cb << 20);
sa1bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, memory::cartrom, mmio.cb << 20);
unsigned addr = mmio.cb << 20;
Memory &access = mmio_access(addr);
if(mmio.cbmode == 0) {
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
} else {
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
memory::vectorsp.sync();
}
//(DXB) Super MMC bank D
@@ -161,10 +174,19 @@ void SA1::mmio_w2221(uint8_t data) {
mmio.dbmode = (data & 0x80);
mmio.db = (data & 0x07);
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, (mmio.dbmode == 0) ? 0x100000 : (mmio.db << 20));
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, memory::cartrom, mmio.db << 20);
sa1bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, memory::cartrom, mmio.db << 20);
unsigned addr = mmio.db << 20;
Memory &access = mmio_access(addr);
if(mmio.dbmode == 0) {
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
} else {
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
}
//(EXB) Super MMC bank E
@@ -172,10 +194,19 @@ void SA1::mmio_w2222(uint8_t data) {
mmio.ebmode = (data & 0x80);
mmio.eb = (data & 0x07);
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, (mmio.ebmode == 0) ? 0x200000 : (mmio.eb << 20));
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, memory::cartrom, mmio.eb << 20);
sa1bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, memory::cartrom, mmio.eb << 20);
unsigned addr = mmio.eb << 20;
Memory &access = mmio_access(addr);
if(mmio.ebmode == 0) {
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
} else {
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
}
//(FXB) Super MMC bank F
@@ -183,18 +214,27 @@ void SA1::mmio_w2223(uint8_t data) {
mmio.fbmode = (data & 0x80);
mmio.fb = (data & 0x07);
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, (mmio.fbmode == 0) ? 0x300000 : (mmio.fb << 20));
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, memory::cartrom, mmio.fb << 20);
sa1bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, memory::cartrom, mmio.fb << 20);
unsigned addr = mmio.fb << 20;
Memory &access = mmio_access(addr);
if(mmio.fbmode == 0) {
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
} else {
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
}
//(BMAPS) S-CPU BW-RAM address mapping
void SA1::mmio_w2224(uint8_t data) {
mmio.sbm = (data & 0x1f);
bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cpu::bwram, mmio.sbm * 0x2000, 0x2000);
bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cpu::bwram, mmio.sbm * 0x2000, 0x2000);
bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
}
//(BMAP) SA-1 BW-RAM address mapping
@@ -204,12 +244,12 @@ void SA1::mmio_w2225(uint8_t data) {
if(mmio.sw46 == 0) {
//$[40-43]:[0000-ffff] x 32 projection
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
} else {
//$[60-6f]:[0000-ffff] x 128 projection
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1::bitmapram, mmio.cbm * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1::bitmapram, mmio.cbm * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
}
}
@@ -256,7 +296,7 @@ void SA1::mmio_w2231(uint8_t data) {
mmio.dmasize = (data >> 2) & 7;
mmio.dmacb = (data & 0x03);
if(mmio.chdend) memory::cpu::bwram.cc1dma = false;
if(mmio.chdend) memory::cc1bwram.dma = false;
if(mmio.dmasize > 5) mmio.dmasize = 5;
if(mmio.dmacb > 2) mmio.dmacb = 2;
}
@@ -274,11 +314,11 @@ void SA1::mmio_w2235(uint8_t data) {
void SA1::mmio_w2236(uint8_t data) {
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
if(dma.mode == DMA::Inactive) {
if(mmio.dmaen == true) {
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
dma.mode = DMA::Normal;
dma_normal();
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
dma.mode = DMA::CC1;
dma_cc1();
}
}
}
@@ -286,9 +326,9 @@ void SA1::mmio_w2236(uint8_t data) {
void SA1::mmio_w2237(uint8_t data) {
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
if(dma.mode == DMA::Inactive) {
if(mmio.dmaen == true) {
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
dma.mode = DMA::Normal;
dma_normal();
}
}
}
@@ -311,9 +351,9 @@ void SA1::mmio_w2244(uint8_t data) { mmio.brf[ 4] = data; }
void SA1::mmio_w2245(uint8_t data) { mmio.brf[ 5] = data; }
void SA1::mmio_w2246(uint8_t data) { mmio.brf[ 6] = data; }
void SA1::mmio_w2247(uint8_t data) { mmio.brf[ 7] = data;
if(dma.mode == DMA::Inactive) {
if(mmio.dmaen == true) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dma.mode = DMA::CC2;
dma_cc2();
}
}
}
@@ -326,9 +366,9 @@ void SA1::mmio_w224c(uint8_t data) { mmio.brf[12] = data; }
void SA1::mmio_w224d(uint8_t data) { mmio.brf[13] = data; }
void SA1::mmio_w224e(uint8_t data) { mmio.brf[14] = data; }
void SA1::mmio_w224f(uint8_t data) { mmio.brf[15] = data;
if(dma.mode == DMA::Inactive) {
if(mmio.dmaen == true) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dma.mode = DMA::CC2;
dma_cc2();
}
}
}
@@ -384,7 +424,7 @@ void SA1::mmio_w2254(uint8_t data) {
mmio.mr += (int16_t)mmio.ma * (int16_t)mmio.mb;
mmio.overflow = (mmio.mr >= (1ULL << 40));
mmio.mr &= (1ULL << 40) - 1;
mmio.ma = 0;
mmio.mb = 0;
}
}

View File

@@ -1,5 +1,6 @@
uint8_t mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8_t data);
Memory& mmio_access(unsigned &addr);
struct MMIO {
//$2200 CCNT

View File

@@ -1,8 +1,10 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#define SA1_CPP
#include "sa1.hpp"
#define SA1_CPP
namespace SNES {
SA1 sa1;
#include "bus/bus.cpp"
#include "dma/dma.cpp"
#include "memory/memory.cpp"
@@ -12,17 +14,10 @@ void SA1::enter() {
while(true) {
while(mmio.sa1_rdyb || mmio.sa1_resb) {
//SA-1 co-processor is asleep
add_clocks(4);
tick();
scheduler.sync_copcpu();
}
#if 0
static FILE *fp = fopen("/home/byuu/Desktop/sa1log.txt", "wb");
char t[1024];
disassemble_opcode(t);
fprintf(fp, "%s\n", t);
#endif
if(status.interrupt_pending) {
status.interrupt_pending = false;
interrupt(status.interrupt_vector);
@@ -39,33 +34,23 @@ void SA1::last_cycle() {
mmio.sa1_nmifl = true;
mmio.sa1_nmicl = 1;
regs.wai = false;
return;
}
if(mmio.timer_irqen && !mmio.timer_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.timer_irqfl = true;
mmio.timer_irqcl = 1;
regs.wai = false;
return;
}
if(mmio.dma_irqen && !mmio.dma_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.dma_irqfl = true;
mmio.dma_irqcl = 1;
regs.wai = false;
return;
}
if(!regs.p.i && mmio.sa1_irq && !mmio.sa1_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.sa1_irqfl = true;
regs.wai = false;
return;
} else if(!regs.p.i) {
if(mmio.timer_irqen && !mmio.timer_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.timer_irqfl = true;
regs.wai = false;
} else if(mmio.dma_irqen && !mmio.dma_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.dma_irqfl = true;
regs.wai = false;
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
status.interrupt_pending = true;
status.interrupt_vector = mmio.civ;
mmio.sa1_irqfl = true;
regs.wai = false;
}
}
}
@@ -76,7 +61,6 @@ void SA1::interrupt(uint16_t vector) {
op_writestack(regs.pc.h);
op_writestack(regs.pc.l);
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
add_clocks(8);
regs.pc.w = vector;
regs.pc.b = 0x00;
regs.p.i = 1;
@@ -87,47 +71,37 @@ bool SA1::interrupt_pending() {
return status.interrupt_pending;
}
void SA1::add_clocks(unsigned clocks) {
scheduler.addclocks_cop(clocks);
uint16_t last_hcounter = status.hcounter;
uint16_t last_vcounter = status.vcounter;
void SA1::tick() {
scheduler.addclocks_cop(2);
//adjust counters:
//note that internally, status counters are in clocks;
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
if(mmio.hvselb == 0) {
//HV timer
status.hcounter += clocks;
status.hcounter += 2;
if(status.hcounter >= 1364) {
status.hcounter -= 1364;
status.vcounter++;
if(status.vcounter >= status.scanlines) {
status.vcounter = 0;
}
status.hcounter = 0;
if(++status.vcounter >= status.scanlines) status.vcounter = 0;
}
} else {
//linear timer
status.hcounter += clocks;
status.hcounter += 2;
status.vcounter += (status.hcounter >> 11);
status.hcounter &= 0x07ff;
status.vcounter &= 0x01ff;
}
//test counters for timer IRQ
uint32_t lo = (last_vcounter << 11) + last_hcounter;
uint32_t hi = (status.vcounter << 11) + status.hcounter;
uint32_t trigger = (mmio.vcnt << 11) + (mmio.hcnt << 2);
if(lo > hi) {
if(trigger <= hi) goto trigger_irq;
hi += 1 << 20;
switch((mmio.ven << 1) + (mmio.hen << 0)) {
case 0: break;
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
}
}
if(lo < trigger && trigger <= hi) goto trigger_irq;
return;
trigger_irq:
void SA1::trigger_irq() {
mmio.timer_irqfl = true;
if(mmio.timer_irqen) mmio.timer_irqcl = 0;
}
@@ -146,6 +120,11 @@ void SA1::power() {
}
void SA1::reset() {
memory::vectorsp.access = 0;
memory::cc1bwram.dma = false;
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
memory::iram.write(addr, 0x00);
}
sa1bus.init();
regs.pc.d = 0x000000;
@@ -160,19 +139,14 @@ void SA1::reset() {
regs.wai = false;
update_table();
memset(iram, 0, sizeof iram);
status.interrupt_pending = false;
status.interrupt_vector = 0x0000;
status.scanlines = (snes.region() == SNES::NTSC ? 261 : 311);
status.scanlines = (system.region() == System::NTSC ? 262 : 312);
status.vcounter = 0;
status.hcounter = 0;
dma.mode = DMA::Inactive;
dma.clocks = 4;
dma.tile = 0;
dma.line = 0;
dma.line = 0;
//$2200 CCNT
mmio.sa1_irq = false;
@@ -339,3 +313,5 @@ void SA1::reset() {
SA1::SA1() {
}
};

View File

@@ -5,7 +5,6 @@ public:
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
uint8_t iram[2048];
struct Status {
bool interrupt_pending;
@@ -18,10 +17,11 @@ public:
void enter();
void interrupt(uint16_t vector);
void add_clocks(unsigned);
void tick();
void last_cycle();
bool interrupt_pending();
alwaysinline void trigger_irq();
alwaysinline void last_cycle();
alwaysinline bool interrupt_pending();
void init();
void enable();

View File

@@ -1,158 +1,162 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#define SDD1_CPP
#include "sdd1.hpp"
#include "sdd1emu.cpp"
void SDD1::init() {}
void SDD1::enable() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::read()
for(unsigned i = 0x4300; i <= 0x437f; i++) {
cpu_mmio[i & 0x7f] = memory::mmio.get(i);
memory::mmio.map(i, *this);
}
//hook S-DD1 MMIO registers
for(unsigned i = 0x4800; i <= 0x4807; i++) {
memory::mmio.map(i, *this);
}
}
void SDD1::power() {
reset();
}
void SDD1::reset() {
sdd1_enable = 0x00;
xfer_enable = 0x00;
mmc[0] = 0 << 20;
mmc[1] = 1 << 20;
mmc[2] = 2 << 20;
mmc[3] = 3 << 20;
for(unsigned i = 0; i < 8; i++) {
dma[i].addr = 0;
dma[i].size = 0;
}
buffer.ready = false;
bus.map(Bus::MapDirect, 0xc0, 0xff, 0x0000, 0xffff, *this);
}
uint8 SDD1::mmio_read(unsigned addr) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
return cpu_mmio[addr & 0x7f]->mmio_read(addr);
}
switch(addr) {
case 0x4804: return (mmc[0] >> 20) & 7;
case 0x4805: return (mmc[1] >> 20) & 7;
case 0x4806: return (mmc[2] >> 20) & 7;
case 0x4807: return (mmc[3] >> 20) & 7;
}
return cpu.regs.mdr;
}
void SDD1::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
unsigned channel = (addr >> 4) & 7;
switch(addr & 15) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu_mmio[addr & 0x7f]->mmio_write(addr, data);
}
switch(addr) {
case 0x4800: sdd1_enable = data; break;
case 0x4801: xfer_enable = data; break;
case 0x4804: mmc[0] = (data & 7) << 20; break;
case 0x4805: mmc[1] = (data & 7) << 20; break;
case 0x4806: mmc[2] = (data & 7) << 20; break;
case 0x4807: mmc[3] = (data & 7) << 20; break;
}
}
//SDD1::read() is mapped to $[c0-ff]:[0000-ffff]
//the design is meant to be as close to the hardware design as possible, thus this code
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
//
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
//it could see $420b writes (eg it would know when the transfer should begin.)
//
//the hardware needs a way to distinguish program code after $4801 writes from DMA
//decompression that follows soon after.
//
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
//
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
uint8 SDD1::read(unsigned addr) {
if(sdd1_enable & xfer_enable) {
//at least one channel has S-DD1 decompression enabled ...
for(unsigned i = 0; i < 8; i++) {
if(sdd1_enable & xfer_enable & (1 << i)) {
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
if(addr == dma[i].addr) {
if(!buffer.ready) {
//first byte read for channel performs full decompression.
//this really should stream byte-by-byte, but it's not necessary since the size is known
buffer.offset = 0;
buffer.size = dma[i].size ? dma[i].size : 65536;
//sdd1emu calls this function; it needs to access uncompressed data;
//so temporarily disable decompression mode for decompress() call.
uint8 temp = sdd1_enable;
sdd1_enable = false;
sdd1emu.decompress(addr, buffer.size, buffer.data);
sdd1_enable = temp;
buffer.ready = true;
}
//fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
uint8 data = buffer.data[(uint16)buffer.offset++];
if(buffer.offset >= buffer.size) {
buffer.ready = false;
xfer_enable &= ~(1 << i);
}
return data;
} //address matched
} //channel enabled
} //channel loop
} //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
}
void SDD1::write(unsigned addr, uint8 data) {
}
SDD1::SDD1() {
buffer.data = new uint8[65536];
}
SDD1::~SDD1() {
delete[] buffer.data;
}
#include <../base.hpp>
#define SDD1_CPP
namespace SNES {
SDD1 sdd1;
#include "sdd1emu.cpp"
void SDD1::init() {}
void SDD1::enable() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::read()
for(unsigned i = 0x4300; i <= 0x437f; i++) {
cpu_mmio[i & 0x7f] = memory::mmio.mmio[i - 0x2000];
memory::mmio.map(i, *this);
}
//hook S-DD1 MMIO registers
for(unsigned i = 0x4800; i <= 0x4807; i++) {
memory::mmio.map(i, *this);
}
}
void SDD1::power() {
reset();
}
void SDD1::reset() {
sdd1_enable = 0x00;
xfer_enable = 0x00;
mmc[0] = 0 << 20;
mmc[1] = 1 << 20;
mmc[2] = 2 << 20;
mmc[3] = 3 << 20;
for(unsigned i = 0; i < 8; i++) {
dma[i].addr = 0;
dma[i].size = 0;
}
buffer.ready = false;
bus.map(Bus::MapDirect, 0xc0, 0xff, 0x0000, 0xffff, *this);
}
uint8 SDD1::mmio_read(unsigned addr) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
return cpu_mmio[addr & 0x7f]->mmio_read(addr);
}
switch(addr) {
case 0x4804: return (mmc[0] >> 20) & 7;
case 0x4805: return (mmc[1] >> 20) & 7;
case 0x4806: return (mmc[2] >> 20) & 7;
case 0x4807: return (mmc[3] >> 20) & 7;
}
return cpu.regs.mdr;
}
void SDD1::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
unsigned channel = (addr >> 4) & 7;
switch(addr & 15) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu_mmio[addr & 0x7f]->mmio_write(addr, data);
}
switch(addr) {
case 0x4800: sdd1_enable = data; break;
case 0x4801: xfer_enable = data; break;
case 0x4804: mmc[0] = (data & 7) << 20; break;
case 0x4805: mmc[1] = (data & 7) << 20; break;
case 0x4806: mmc[2] = (data & 7) << 20; break;
case 0x4807: mmc[3] = (data & 7) << 20; break;
}
}
//SDD1::read() is mapped to $[c0-ff]:[0000-ffff]
//the design is meant to be as close to the hardware design as possible, thus this code
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
//
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
//it could see $420b writes (eg it would know when the transfer should begin.)
//
//the hardware needs a way to distinguish program code after $4801 writes from DMA
//decompression that follows soon after.
//
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
//
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
uint8 SDD1::read(unsigned addr) {
if(sdd1_enable & xfer_enable) {
//at least one channel has S-DD1 decompression enabled ...
for(unsigned i = 0; i < 8; i++) {
if(sdd1_enable & xfer_enable & (1 << i)) {
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
if(addr == dma[i].addr) {
if(!buffer.ready) {
//first byte read for channel performs full decompression.
//this really should stream byte-by-byte, but it's not necessary since the size is known
buffer.offset = 0;
buffer.size = dma[i].size ? dma[i].size : 65536;
//sdd1emu calls this function; it needs to access uncompressed data;
//so temporarily disable decompression mode for decompress() call.
uint8 temp = sdd1_enable;
sdd1_enable = false;
sdd1emu.decompress(addr, buffer.size, buffer.data);
sdd1_enable = temp;
buffer.ready = true;
}
//fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
uint8 data = buffer.data[(uint16)buffer.offset++];
if(buffer.offset >= buffer.size) {
buffer.ready = false;
xfer_enable &= ~(1 << i);
}
return data;
} //address matched
} //channel enabled
} //channel loop
} //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
}
void SDD1::write(unsigned addr, uint8 data) {
}
SDD1::SDD1() {
buffer.data = new uint8[65536];
}
SDD1::~SDD1() {
delete[] buffer.data;
}
};

View File

@@ -1,40 +1,40 @@
#include "sdd1emu.hpp"
class SDD1 : public MMIO, public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
SDD1();
~SDD1();
private:
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
uint8 sdd1_enable; //channel bit-mask
uint8 xfer_enable; //channel bit-mask
unsigned mmc[4]; //memory map controller ROM indices
struct {
unsigned addr; //$43x2-$43x4 -- DMA transfer address
uint16 size; //$43x5-$43x6 -- DMA transfer size
} dma[8];
SDD1emu sdd1emu;
struct {
uint8 *data; //pointer to decompressed S-DD1 data (65536 bytes)
uint16 offset; //read index into S-DD1 decompression buffer
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
} buffer;
};
extern SDD1 sdd1;
#include "sdd1emu.hpp"
class SDD1 : public MMIO, public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
SDD1();
~SDD1();
private:
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
uint8 sdd1_enable; //channel bit-mask
uint8 xfer_enable; //channel bit-mask
unsigned mmc[4]; //memory map controller ROM indices
struct {
unsigned addr; //$43x2-$43x4 -- DMA transfer address
uint16 size; //$43x5-$43x6 -- DMA transfer size
} dma[8];
SDD1emu sdd1emu;
struct {
uint8 *data; //pointer to decompressed S-DD1 data (65536 bytes)
uint16 offset; //read index into S-DD1 decompression buffer
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
} buffer;
};
extern SDD1 sdd1;

View File

@@ -1,451 +1,451 @@
#ifdef SDD1_CPP
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
#define SDD1_read(__addr) (sdd1.read(__addr))
////////////////////////////////////////////////////
void SDD1_IM::prepareDecomp(uint32 in_buf) {
byte_ptr=in_buf;
bit_count=4;
}
////////////////////////////////////////////////////
uint8 SDD1_IM::getCodeword(uint8 code_len) {
uint8 codeword;
uint8 comp_count;
codeword = (SDD1_read(byte_ptr))<<bit_count;
++bit_count;
if (codeword & 0x80) {
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
bit_count+=code_len;
}
if (bit_count & 0x08) {
byte_ptr++;
bit_count&=0x07;
}
return codeword;
}
//////////////////////////////////////////////////////
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
IM(associatedIM)
{
}
//////////////////////////////////////////////////////
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
const uint8 run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
uint8 codeword=IM->getCodeword(code_num);
if (codeword & 0x80) {
*LPSind=1;
*MPScount=run_count[codeword>>(code_num^0x07)];
}
else {
*MPScount=(1<<code_num);
}
}
///////////////////////////////////////////////////////
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
GCD(associatedGCD), code_num(code)
{
}
///////////////////////////////////////////////
void SDD1_BG::prepareDecomp(void) {
MPScount=0;
LPSind=0;
}
//////////////////////////////////////////////
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
uint8 bit;
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
if (MPScount) {
bit=0;
MPScount--;
}
else {
bit=1;
LPSind=0;
}
if (MPScount || LPSind) (*endOfRun)=0;
else (*endOfRun)=1;
return bit;
}
/////////////////////////////////////////////////
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
BG[0]=associatedBG0;
BG[1]=associatedBG1;
BG[2]=associatedBG2;
BG[3]=associatedBG3;
BG[4]=associatedBG4;
BG[5]=associatedBG5;
BG[6]=associatedBG6;
BG[7]=associatedBG7;
}
/////////////////////////////////////////////////////////
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
//////////////////////////////////////////////////////
void SDD1_PEM::prepareDecomp(void) {
for (uint8 i=0; i<32; i++) {
contextInfo[i].status=0;
contextInfo[i].MPS=0;
}
}
/////////////////////////////////////////////////////////
uint8 SDD1_PEM::getBit(uint8 context) {
bool8 endOfRun;
uint8 bit;
SDD1_ContextInfo *pContInfo=&contextInfo[context];
uint8 currStatus = pContInfo->status;
const state *pState=&SDD1_PEM::evolution_table[currStatus];
uint8 currentMPS=pContInfo->MPS;
bit=(BG[pState->code_num])->getBit(&endOfRun);
if (endOfRun)
if (bit) {
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
(pContInfo->status)=pState->nextIfLPS;
}
else
(pContInfo->status)=pState->nextIfMPS;
return bit^currentMPS;
}
//////////////////////////////////////////////////////////////
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
PEM(associatedPEM)
{
}
//////////////////////////////////////////////////////////////
void SDD1_CM::prepareDecomp(uint32 first_byte) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
contextBitsInfo = SDD1_read(first_byte) & 0x30;
bit_number=0;
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
switch (bitplanesInfo) {
case 0x00:
currBitplane = 1;
break;
case 0x40:
currBitplane = 7;
break;
case 0x80:
currBitplane = 3;
}
}
/////////////////////////////////////////////////////////////
uint8 SDD1_CM::getBit(void) {
uint8 currContext;
uint16 *context_bits;
switch (bitplanesInfo) {
case 0x00:
currBitplane ^= 0x01;
break;
case 0x40:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
break;
case 0x80:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
break;
case 0xc0:
currBitplane = bit_number & 0x07;
}
context_bits = &prevBitplaneBits[currBitplane];
currContext=(currBitplane & 0x01)<<4;
switch (contextBitsInfo) {
case 0x00:
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
break;
case 0x10:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
break;
case 0x20:
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
break;
case 0x30:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
}
uint8 bit=PEM->getBit(currContext);
*context_bits <<= 1;
*context_bits |= bit;
bit_number++;
return bit;
}
//////////////////////////////////////////////////
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
CM(associatedCM)
{
}
///////////////////////////////////////////////////
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
length=out_len;
buffer=out_buf;
}
///////////////////////////////////////////////////
void SDD1_OL::launch(void) {
uint8 i;
uint8 register1, register2;
switch (bitplanesInfo) {
case 0x00:
case 0x40:
case 0x80:
i=1;
do { //if length==0, we output 2^16 bytes
if (!i) {
*(buffer++)=register2;
i=~i;
}
else {
for (register1=register2=0, i=0x80; i; i>>=1) {
if (CM->getBit()) register1 |= i;
if (CM->getBit()) register2 |= i;
}
*(buffer++)=register1;
}
} while (--length);
break;
case 0xc0:
do {
for (register1=0, i=0x01; i; i<<=1) {
if (CM->getBit()) register1 |= i;
}
*(buffer++)=register1;
} while (--length);
}
}
///////////////////////////////////////////////////////
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
IM.prepareDecomp(in_buf);
BG0.prepareDecomp();
BG1.prepareDecomp();
BG2.prepareDecomp();
BG3.prepareDecomp();
BG4.prepareDecomp();
BG5.prepareDecomp();
BG6.prepareDecomp();
BG7.prepareDecomp();
PEM.prepareDecomp();
CM.prepareDecomp(in_buf);
OL.prepareDecomp(in_buf, out_len, out_buf);
OL.launch();
}
////////////////////////////////////////////////////////////
SDD1emu::SDD1emu() :
GCD(&IM),
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
CM(&PEM),
OL(&CM)
{
}
///////////////////////////////////////////////////////////
/************************************************************************
#endif
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
#define SDD1_read(__addr) (sdd1.read(__addr))
////////////////////////////////////////////////////
void SDD1_IM::prepareDecomp(uint32 in_buf) {
byte_ptr=in_buf;
bit_count=4;
}
////////////////////////////////////////////////////
uint8 SDD1_IM::getCodeword(uint8 code_len) {
uint8 codeword;
uint8 comp_count;
codeword = (SDD1_read(byte_ptr))<<bit_count;
++bit_count;
if (codeword & 0x80) {
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
bit_count+=code_len;
}
if (bit_count & 0x08) {
byte_ptr++;
bit_count&=0x07;
}
return codeword;
}
//////////////////////////////////////////////////////
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
IM(associatedIM)
{
}
//////////////////////////////////////////////////////
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
const uint8 run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
uint8 codeword=IM->getCodeword(code_num);
if (codeword & 0x80) {
*LPSind=1;
*MPScount=run_count[codeword>>(code_num^0x07)];
}
else {
*MPScount=(1<<code_num);
}
}
///////////////////////////////////////////////////////
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
GCD(associatedGCD), code_num(code)
{
}
///////////////////////////////////////////////
void SDD1_BG::prepareDecomp(void) {
MPScount=0;
LPSind=0;
}
//////////////////////////////////////////////
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
uint8 bit;
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
if (MPScount) {
bit=0;
MPScount--;
}
else {
bit=1;
LPSind=0;
}
if (MPScount || LPSind) (*endOfRun)=0;
else (*endOfRun)=1;
return bit;
}
/////////////////////////////////////////////////
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
BG[0]=associatedBG0;
BG[1]=associatedBG1;
BG[2]=associatedBG2;
BG[3]=associatedBG3;
BG[4]=associatedBG4;
BG[5]=associatedBG5;
BG[6]=associatedBG6;
BG[7]=associatedBG7;
}
/////////////////////////////////////////////////////////
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
//////////////////////////////////////////////////////
void SDD1_PEM::prepareDecomp(void) {
for (uint8 i=0; i<32; i++) {
contextInfo[i].status=0;
contextInfo[i].MPS=0;
}
}
/////////////////////////////////////////////////////////
uint8 SDD1_PEM::getBit(uint8 context) {
bool8 endOfRun;
uint8 bit;
SDD1_ContextInfo *pContInfo=&contextInfo[context];
uint8 currStatus = pContInfo->status;
const state *pState=&SDD1_PEM::evolution_table[currStatus];
uint8 currentMPS=pContInfo->MPS;
bit=(BG[pState->code_num])->getBit(&endOfRun);
if (endOfRun)
if (bit) {
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
(pContInfo->status)=pState->nextIfLPS;
}
else
(pContInfo->status)=pState->nextIfMPS;
return bit^currentMPS;
}
//////////////////////////////////////////////////////////////
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
PEM(associatedPEM)
{
}
//////////////////////////////////////////////////////////////
void SDD1_CM::prepareDecomp(uint32 first_byte) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
contextBitsInfo = SDD1_read(first_byte) & 0x30;
bit_number=0;
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
switch (bitplanesInfo) {
case 0x00:
currBitplane = 1;
break;
case 0x40:
currBitplane = 7;
break;
case 0x80:
currBitplane = 3;
}
}
/////////////////////////////////////////////////////////////
uint8 SDD1_CM::getBit(void) {
uint8 currContext;
uint16 *context_bits;
switch (bitplanesInfo) {
case 0x00:
currBitplane ^= 0x01;
break;
case 0x40:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
break;
case 0x80:
currBitplane ^= 0x01;
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
break;
case 0xc0:
currBitplane = bit_number & 0x07;
}
context_bits = &prevBitplaneBits[currBitplane];
currContext=(currBitplane & 0x01)<<4;
switch (contextBitsInfo) {
case 0x00:
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
break;
case 0x10:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
break;
case 0x20:
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
break;
case 0x30:
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
}
uint8 bit=PEM->getBit(currContext);
*context_bits <<= 1;
*context_bits |= bit;
bit_number++;
return bit;
}
//////////////////////////////////////////////////
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
CM(associatedCM)
{
}
///////////////////////////////////////////////////
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
length=out_len;
buffer=out_buf;
}
///////////////////////////////////////////////////
void SDD1_OL::launch(void) {
uint8 i;
uint8 register1, register2;
switch (bitplanesInfo) {
case 0x00:
case 0x40:
case 0x80:
i=1;
do { //if length==0, we output 2^16 bytes
if (!i) {
*(buffer++)=register2;
i=~i;
}
else {
for (register1=register2=0, i=0x80; i; i>>=1) {
if (CM->getBit()) register1 |= i;
if (CM->getBit()) register2 |= i;
}
*(buffer++)=register1;
}
} while (--length);
break;
case 0xc0:
do {
for (register1=0, i=0x01; i; i<<=1) {
if (CM->getBit()) register1 |= i;
}
*(buffer++)=register1;
} while (--length);
}
}
///////////////////////////////////////////////////////
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
IM.prepareDecomp(in_buf);
BG0.prepareDecomp();
BG1.prepareDecomp();
BG2.prepareDecomp();
BG3.prepareDecomp();
BG4.prepareDecomp();
BG5.prepareDecomp();
BG6.prepareDecomp();
BG7.prepareDecomp();
PEM.prepareDecomp();
CM.prepareDecomp(in_buf);
OL.prepareDecomp(in_buf, out_len, out_buf);
OL.launch();
}
////////////////////////////////////////////////////////////
SDD1emu::SDD1emu() :
GCD(&IM),
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
CM(&PEM),
OL(&CM)
{
}
///////////////////////////////////////////////////////////
#endif

View File

@@ -1,162 +1,162 @@
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
typedef uint8_t bool8;
class SDD1_IM { //Input Manager
public:
SDD1_IM(void) {}
void prepareDecomp(uint32 in_buf);
uint8 getCodeword(const uint8 code_len);
private:
uint32 byte_ptr;
uint8 bit_count;
};
////////////////////////////////////////////////////
class SDD1_GCD { //Golomb-Code Decoder
public:
SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
private:
SDD1_IM *const IM;
};
//////////////////////////////////////////////////////
class SDD1_BG { // Bits Generator
public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
void prepareDecomp(void);
uint8 getBit(bool8 *endOfRun);
private:
const uint8 code_num;
uint8 MPScount;
bool8 LPSind;
SDD1_GCD *const GCD;
};
////////////////////////////////////////////////
class SDD1_PEM { //Probability Estimation Module
public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void);
uint8 getBit(uint8 context);
private:
struct state {
uint8 code_num;
uint8 nextIfMPS;
uint8 nextIfLPS;
};
static const state evolution_table[];
struct SDD1_ContextInfo {
uint8 status;
uint8 MPS;
} contextInfo[32];
SDD1_BG * BG[8];
};
///////////////////////////////////////////////////
class SDD1_CM { //Context Model
public:
SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint32 first_byte);
uint8 getBit(void);
private:
uint8 bitplanesInfo;
uint8 contextBitsInfo;
uint8 bit_number;
uint8 currBitplane;
uint16 prevBitplaneBits[8];
SDD1_PEM *const PEM;
};
///////////////////////////////////////////////////
class SDD1_OL { //Output Logic
public:
SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
void launch(void);
private:
uint8 bitplanesInfo;
uint16 length;
uint8 *buffer;
SDD1_CM *const CM;
};
/////////////////////////////////////////////////////////
class SDD1emu {
public:
SDD1emu(void);
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
private:
SDD1_IM IM;
SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM;
SDD1_CM CM;
SDD1_OL OL;
};
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
typedef uint8_t bool8;
class SDD1_IM { //Input Manager
public:
SDD1_IM(void) {}
void prepareDecomp(uint32 in_buf);
uint8 getCodeword(const uint8 code_len);
private:
uint32 byte_ptr;
uint8 bit_count;
};
////////////////////////////////////////////////////
class SDD1_GCD { //Golomb-Code Decoder
public:
SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
private:
SDD1_IM *const IM;
};
//////////////////////////////////////////////////////
class SDD1_BG { // Bits Generator
public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
void prepareDecomp(void);
uint8 getBit(bool8 *endOfRun);
private:
const uint8 code_num;
uint8 MPScount;
bool8 LPSind;
SDD1_GCD *const GCD;
};
////////////////////////////////////////////////
class SDD1_PEM { //Probability Estimation Module
public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void);
uint8 getBit(uint8 context);
private:
struct state {
uint8 code_num;
uint8 nextIfMPS;
uint8 nextIfLPS;
};
static const state evolution_table[];
struct SDD1_ContextInfo {
uint8 status;
uint8 MPS;
} contextInfo[32];
SDD1_BG * BG[8];
};
///////////////////////////////////////////////////
class SDD1_CM { //Context Model
public:
SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint32 first_byte);
uint8 getBit(void);
private:
uint8 bitplanesInfo;
uint8 contextBitsInfo;
uint8 bit_number;
uint8 currBitplane;
uint16 prevBitplaneBits[8];
SDD1_PEM *const PEM;
};
///////////////////////////////////////////////////
class SDD1_OL { //Output Logic
public:
SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
void launch(void);
private:
uint8 bitplanesInfo;
uint16 length;
uint8 *buffer;
SDD1_CM *const CM;
};
/////////////////////////////////////////////////////////
class SDD1emu {
public:
SDD1emu(void);
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
private:
SDD1_IM IM;
SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM;
SDD1_CM CM;
SDD1_OL OL;
};

65
src/chip/sgb/sgb.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include <../base.hpp>
#define SGB_CPP
namespace SNES {
SuperGameBoy sgb;
void SuperGameBoy::enter() {
while(true) {
if(sgb_run) {
unsigned samples = sgb_run(samplebuffer, 16);
scheduler.addclocks_cop(samples * 10);
scheduler.sync_copcpu();
} else {
scheduler.addclocks_cop(64 * 1024 * 1024);
scheduler.sync_copcpu();
}
}
}
uint8_t SuperGameBoy::read(unsigned addr) {
addr &= 0xffff;
if(sgb_read) return sgb_read(addr);
return 0x00;
}
void SuperGameBoy::write(unsigned addr, uint8_t data) {
addr &= 0xffff;
if(sgb_write) return sgb_write(addr, data);
}
void SuperGameBoy::init() {
if(libsgb.open("SuperGameBoy")) {
sgb_init = libsgb.sym("sgb_init");
sgb_term = libsgb.sym("sgb_term");
sgb_power = libsgb.sym("sgb_power");
sgb_reset = libsgb.sym("sgb_reset");
sgb_read = libsgb.sym("sgb_read");
sgb_write = libsgb.sym("sgb_write");
sgb_run = libsgb.sym("sgb_run");
}
}
void SuperGameBoy::enable() {
}
void SuperGameBoy::power() {
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
if(sgb_init) {
sgb_init(SGB2,
memory::gbrom.data(), memory::gbrom.size(),
memory::gbram.data(), memory::gbram.size()
);
}
if(sgb_power) sgb_power();
}
void SuperGameBoy::reset() {
if(sgb_reset) sgb_reset();
}
};

27
src/chip/sgb/sgb.hpp Normal file
View File

@@ -0,0 +1,27 @@
class SuperGameBoy : public Memory {
public:
void enter();
uint8_t read(unsigned addr);
void write(unsigned addr, uint8_t data);
void init();
void enable();
void power();
void reset();
private:
library libsgb;
uint32_t samplebuffer[4096];
enum { SGB1 = 0, SGB2 = 1 };
function<bool (bool, uint8_t*, unsigned, uint8_t*, unsigned)> sgb_init;
function<void ()> sgb_term;
function<void ()> sgb_power;
function<void ()> sgb_reset;
function<uint8_t (unsigned)> sgb_read;
function<void (unsigned, uint8_t)> sgb_write;
function<unsigned (uint32_t*, unsigned)> sgb_run;
};
extern SuperGameBoy sgb;

View File

@@ -1,8 +1,10 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#define SPC7110_CPP
#include "spc7110.hpp"
#define SPC7110_CPP
namespace SNES {
SPC7110 spc7110;
#include "decomp.cpp"
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
@@ -670,3 +672,5 @@ void SPC7110::write(unsigned addr, uint8 data) {
SPC7110::SPC7110() {
}
};

View File

@@ -1,6 +1,9 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#include "srtc.hpp"
#define SRTC_CPP
namespace SNES {
SRTC srtc;
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
@@ -224,3 +227,5 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
SRTC::SRTC() {
}
};

View File

@@ -1,87 +1,92 @@
#include <../base.hpp>
#define ST010_CPP
#include "st010.hpp"
#include "st010_data.hpp"
#include "st010_op.cpp"
int16 ST010::sin(int16 theta) {
return sin_table[(theta >> 8) & 0xff];
}
int16 ST010::cos(int16 theta) {
return sin_table[((theta + 0x4000) >> 8) & 0xff];
}
uint8 ST010::readb(uint16 addr) {
return ram[addr & 0xfff];
}
uint16 ST010::readw(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8);
}
uint32 ST010::readd(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8) |
(readb(addr + 2) << 16) |
(readb(addr + 3) << 24);
}
void ST010::writeb(uint16 addr, uint8 data) {
ram[addr & 0xfff] = data;
}
void ST010::writew(uint16 addr, uint16 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
}
void ST010::writed(uint16 addr, uint32 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
writeb(addr + 2, data >> 16);
writeb(addr + 3, data >> 24);
}
//
void ST010::init() {
}
void ST010::enable() {
}
void ST010::power() {
reset();
}
void ST010::reset() {
memset(ram, 0x00, sizeof ram);
}
//
uint8 ST010::read(unsigned addr) {
return readb(addr);
}
void ST010::write(unsigned addr, uint8 data) {
writeb(addr, data);
if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
switch(ram[0x0020]) {
case 0x01: op_01(); break;
case 0x02: op_02(); break;
case 0x03: op_03(); break;
case 0x04: op_04(); break;
case 0x05: op_05(); break;
case 0x06: op_06(); break;
case 0x07: op_07(); break;
case 0x08: op_08(); break;
}
ram[0x0021] &= ~0x80;
}
}
namespace SNES {
ST010 st010;
#include "st010_data.hpp"
#include "st010_op.cpp"
int16 ST010::sin(int16 theta) {
return sin_table[(theta >> 8) & 0xff];
}
int16 ST010::cos(int16 theta) {
return sin_table[((theta + 0x4000) >> 8) & 0xff];
}
uint8 ST010::readb(uint16 addr) {
return ram[addr & 0xfff];
}
uint16 ST010::readw(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8);
}
uint32 ST010::readd(uint16 addr) {
return (readb(addr + 0) << 0) |
(readb(addr + 1) << 8) |
(readb(addr + 2) << 16) |
(readb(addr + 3) << 24);
}
void ST010::writeb(uint16 addr, uint8 data) {
ram[addr & 0xfff] = data;
}
void ST010::writew(uint16 addr, uint16 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
}
void ST010::writed(uint16 addr, uint32 data) {
writeb(addr + 0, data);
writeb(addr + 1, data >> 8);
writeb(addr + 2, data >> 16);
writeb(addr + 3, data >> 24);
}
//
void ST010::init() {
}
void ST010::enable() {
}
void ST010::power() {
reset();
}
void ST010::reset() {
memset(ram, 0x00, sizeof ram);
}
//
uint8 ST010::read(unsigned addr) {
return readb(addr);
}
void ST010::write(unsigned addr, uint8 data) {
writeb(addr, data);
if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
switch(ram[0x0020]) {
case 0x01: op_01(); break;
case 0x02: op_02(); break;
case 0x03: op_03(); break;
case 0x04: op_04(); break;
case 0x05: op_05(); break;
case 0x06: op_06(); break;
case 0x07: op_07(); break;
case 0x08: op_08(); break;
}
ram[0x0021] &= ~0x80;
}
}
};

View File

@@ -1,42 +1,42 @@
class ST010 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
private:
uint8 ram[0x1000];
static const int16 sin_table[256];
static const int16 mode7_scale[176];
static const uint8 arctan[32][32];
//interfaces to sin table
int16 sin(int16 theta);
int16 cos(int16 theta);
//interfaces to ram buffer
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
uint32 readd (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writed(uint16 addr, uint32 data);
//opcodes
void op_01();
void op_02();
void op_03();
void op_04();
void op_05();
void op_06();
void op_07();
void op_08();
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
};
extern ST010 st010;
class ST010 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
private:
uint8 ram[0x1000];
static const int16 sin_table[256];
static const int16 mode7_scale[176];
static const uint8 arctan[32][32];
//interfaces to sin table
int16 sin(int16 theta);
int16 cos(int16 theta);
//interfaces to ram buffer
uint8 readb (uint16 addr);
uint16 readw (uint16 addr);
uint32 readd (uint16 addr);
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writed(uint16 addr, uint32 data);
//opcodes
void op_01();
void op_02();
void op_03();
void op_04();
void op_05();
void op_06();
void op_07();
void op_08();
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
};
extern ST010 st010;

View File

@@ -1,126 +1,126 @@
const int16 ST010::sin_table[256] = {
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
};
const int16 ST010::mode7_scale[176] = {
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
};
const uint8 ST010::arctan[32][32] = {
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
};
const int16 ST010::sin_table[256] = {
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
};
const int16 ST010::mode7_scale[176] = {
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
};
const uint8 ST010::arctan[32][32] = {
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
};

View File

@@ -1,261 +1,261 @@
#ifdef ST010_CPP
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
//bsnes port - Copyright (C) 2007 byuu
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
if((x0 < 0) && (y0 < 0)) {
x1 = -x0;
y1 = -y0;
quadrant = -0x8000;
} else if(x0 < 0) {
x1 = y0;
y1 = -x0;
quadrant = -0x4000;
} else if(y0 < 0) {
x1 = -y0;
y1 = x0;
quadrant = 0x4000;
} else {
x1 = x0;
y1 = y0;
quadrant = 0x0000;
}
while((x1 > 0x1f) || (y1 > 0x1f)) {
if(x1 > 1) { x1 >>= 1; }
if(y1 > 1) { y1 >>= 1; }
}
if(y1 == 0) { quadrant += 0x4000; }
theta = (arctan[y1][x1] << 8) ^ quadrant;
}
//
void ST010::op_01() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 x1, y1, quadrant, theta;
op_01(x0, y0, x1, y1, quadrant, theta);
writew(0x0000, x1);
writew(0x0002, y1);
writew(0x0004, quadrant);
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
writew(0x0010, theta);
}
void ST010::op_02() {
int16 positions = readw(0x0024);
uint16 *places = (uint16*)(ram + 0x0040);
uint16 *drivers = (uint16*)(ram + 0x0080);
bool sorted;
uint16 temp;
if(positions > 1) {
do {
sorted = true;
for(int i = 0; i < positions - 1; i++) {
if(places[i] < places[i + 1]) {
temp = places[i + 1];
places[i + 1] = places[i];
places[i] = temp;
temp = drivers[i + 1];
drivers[i + 1] = drivers[i];
drivers[i] = temp;
sorted = false;
}
}
positions--;
} while(!sorted);
}
}
void ST010::op_03() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 multiplier = readw(0x0004);
int32 x1, y1;
x1 = x0 * multiplier << 1;
y1 = y0 * multiplier << 1;
writed(0x0010, x1);
writed(0x0014, y1);
}
void ST010::op_04() {
int16 x = readw(0x0000);
int16 y = readw(0x0002);
int16 square;
//calculate the vector length of (x,y)
square = (int16)sqrt((double)(y * y + x * x));
writew(0x0010, square);
}
void ST010::op_05() {
int32 dx, dy;
int16 a1, b1, c1;
uint16 o1;
bool wrap = false;
//target (x,y) coordinates
int16 ypos_max = readw(0x00c0);
int16 xpos_max = readw(0x00c2);
//current coordinates and direction
int32 ypos = readd(0x00c4);
int32 xpos = readd(0x00c8);
uint16 rot = readw(0x00cc);
//physics
uint16 speed = readw(0x00d4);
uint16 accel = readw(0x00d6);
uint16 speed_max = readw(0x00d8);
//special condition acknowledgement
int16 system = readw(0x00da);
int16 flags = readw(0x00dc);
//new target coordinates
int16 ypos_new = readw(0x00de);
int16 xpos_new = readw(0x00e0);
//mask upper bit
xpos_new &= 0x7fff;
//get the current distance
dx = xpos_max - (xpos >> 16);
dy = ypos_max - (ypos >> 16);
//quirk: clear and move in9
writew(0x00d2, 0xffff);
writew(0x00da, 0x0000);
//grab the target angle
op_01(dy, dx, a1, b1, c1, (int16&)o1);
//check for wrapping
if(abs(o1 - rot) > 0x8000) {
o1 += 0x8000;
rot += 0x8000;
wrap = true;
}
uint16 old_speed = speed;
//special case
if(abs(o1 - rot) == 0x8000) {
speed = 0x100;
}
//slow down for sharp curves
else if(abs(o1 - rot) >= 0x1000) {
uint32 slow = abs(o1 - rot);
slow >>= 4; //scaling
speed -= slow;
}
//otherwise accelerate
else {
speed += accel;
if(speed > speed_max) {
speed = speed_max; //clip speed
}
}
//prevent negative/positive overflow
if(abs(old_speed - speed) > 0x8000) {
if(old_speed < speed) { speed = 0; }
else speed = 0xff00;
}
//adjust direction by so many degrees
//be careful of negative adjustments
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
if(o1 < rot) { rot -= 0x280; }
else if(o1 > rot) { rot += 0x280; }
}
//turn of wrapping
if(wrap) { rot -= 0x8000; }
//now check the distances (store for later)
dx = (xpos_max << 16) - xpos;
dy = (ypos_max << 16) - ypos;
dx >>= 16;
dy >>= 16;
//if we're in so many units of the target, signal it
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
//announce our new destination and flag it
xpos_max = xpos_new & 0x7fff;
ypos_max = ypos_new;
flags |= 0x08;
}
//update position
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
//quirk: mask upper byte
xpos &= 0x1fffffff;
ypos &= 0x1fffffff;
writew(0x00c0, ypos_max);
writew(0x00c2, xpos_max);
writed(0x00c4, ypos);
writed(0x00c8, xpos);
writew(0x00cc, rot);
writew(0x00d4, speed);
writew(0x00dc, flags);
}
void ST010::op_06() {
int16 multiplicand = readw(0x0000);
int16 multiplier = readw(0x0002);
int32 product;
product = multiplicand * multiplier << 1;
writed(0x0010, product);
}
void ST010::op_07() {
int16 theta = readw(0x0000);
int16 data;
for(int i = 0, offset = 0; i < 176; i++) {
data = mode7_scale[i] * cos(theta) >> 15;
writew(0x00f0 + offset, data);
writew(0x0510 + offset, data);
data = mode7_scale[i] * sin(theta) >> 15;
writew(0x0250 + offset, data);
if(data) { data = ~data; }
writew(0x03b0 + offset, data);
offset += 2;
}
}
void ST010::op_08() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 theta = readw(0x0004);
int16 x1, y1;
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
writew(0x0010, x1);
writew(0x0012, y1);
}
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
//bsnes port - Copyright (C) 2007 byuu
#endif
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
if((x0 < 0) && (y0 < 0)) {
x1 = -x0;
y1 = -y0;
quadrant = -0x8000;
} else if(x0 < 0) {
x1 = y0;
y1 = -x0;
quadrant = -0x4000;
} else if(y0 < 0) {
x1 = -y0;
y1 = x0;
quadrant = 0x4000;
} else {
x1 = x0;
y1 = y0;
quadrant = 0x0000;
}
while((x1 > 0x1f) || (y1 > 0x1f)) {
if(x1 > 1) { x1 >>= 1; }
if(y1 > 1) { y1 >>= 1; }
}
if(y1 == 0) { quadrant += 0x4000; }
theta = (arctan[y1][x1] << 8) ^ quadrant;
}
//
void ST010::op_01() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 x1, y1, quadrant, theta;
op_01(x0, y0, x1, y1, quadrant, theta);
writew(0x0000, x1);
writew(0x0002, y1);
writew(0x0004, quadrant);
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
writew(0x0010, theta);
}
void ST010::op_02() {
int16 positions = readw(0x0024);
uint16 *places = (uint16*)(ram + 0x0040);
uint16 *drivers = (uint16*)(ram + 0x0080);
bool sorted;
uint16 temp;
if(positions > 1) {
do {
sorted = true;
for(int i = 0; i < positions - 1; i++) {
if(places[i] < places[i + 1]) {
temp = places[i + 1];
places[i + 1] = places[i];
places[i] = temp;
temp = drivers[i + 1];
drivers[i + 1] = drivers[i];
drivers[i] = temp;
sorted = false;
}
}
positions--;
} while(!sorted);
}
}
void ST010::op_03() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 multiplier = readw(0x0004);
int32 x1, y1;
x1 = x0 * multiplier << 1;
y1 = y0 * multiplier << 1;
writed(0x0010, x1);
writed(0x0014, y1);
}
void ST010::op_04() {
int16 x = readw(0x0000);
int16 y = readw(0x0002);
int16 square;
//calculate the vector length of (x,y)
square = (int16)sqrt((double)(y * y + x * x));
writew(0x0010, square);
}
void ST010::op_05() {
int32 dx, dy;
int16 a1, b1, c1;
uint16 o1;
bool wrap = false;
//target (x,y) coordinates
int16 ypos_max = readw(0x00c0);
int16 xpos_max = readw(0x00c2);
//current coordinates and direction
int32 ypos = readd(0x00c4);
int32 xpos = readd(0x00c8);
uint16 rot = readw(0x00cc);
//physics
uint16 speed = readw(0x00d4);
uint16 accel = readw(0x00d6);
uint16 speed_max = readw(0x00d8);
//special condition acknowledgement
int16 system = readw(0x00da);
int16 flags = readw(0x00dc);
//new target coordinates
int16 ypos_new = readw(0x00de);
int16 xpos_new = readw(0x00e0);
//mask upper bit
xpos_new &= 0x7fff;
//get the current distance
dx = xpos_max - (xpos >> 16);
dy = ypos_max - (ypos >> 16);
//quirk: clear and move in9
writew(0x00d2, 0xffff);
writew(0x00da, 0x0000);
//grab the target angle
op_01(dy, dx, a1, b1, c1, (int16&)o1);
//check for wrapping
if(abs(o1 - rot) > 0x8000) {
o1 += 0x8000;
rot += 0x8000;
wrap = true;
}
uint16 old_speed = speed;
//special case
if(abs(o1 - rot) == 0x8000) {
speed = 0x100;
}
//slow down for sharp curves
else if(abs(o1 - rot) >= 0x1000) {
uint32 slow = abs(o1 - rot);
slow >>= 4; //scaling
speed -= slow;
}
//otherwise accelerate
else {
speed += accel;
if(speed > speed_max) {
speed = speed_max; //clip speed
}
}
//prevent negative/positive overflow
if(abs(old_speed - speed) > 0x8000) {
if(old_speed < speed) { speed = 0; }
else speed = 0xff00;
}
//adjust direction by so many degrees
//be careful of negative adjustments
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
if(o1 < rot) { rot -= 0x280; }
else if(o1 > rot) { rot += 0x280; }
}
//turn of wrapping
if(wrap) { rot -= 0x8000; }
//now check the distances (store for later)
dx = (xpos_max << 16) - xpos;
dy = (ypos_max << 16) - ypos;
dx >>= 16;
dy >>= 16;
//if we're in so many units of the target, signal it
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
//announce our new destination and flag it
xpos_max = xpos_new & 0x7fff;
ypos_max = ypos_new;
flags |= 0x08;
}
//update position
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
//quirk: mask upper byte
xpos &= 0x1fffffff;
ypos &= 0x1fffffff;
writew(0x00c0, ypos_max);
writew(0x00c2, xpos_max);
writed(0x00c4, ypos);
writed(0x00c8, xpos);
writew(0x00cc, rot);
writew(0x00d4, speed);
writew(0x00dc, flags);
}
void ST010::op_06() {
int16 multiplicand = readw(0x0000);
int16 multiplier = readw(0x0002);
int32 product;
product = multiplicand * multiplier << 1;
writed(0x0010, product);
}
void ST010::op_07() {
int16 theta = readw(0x0000);
int16 data;
for(int i = 0, offset = 0; i < 176; i++) {
data = mode7_scale[i] * cos(theta) >> 15;
writew(0x00f0 + offset, data);
writew(0x0510 + offset, data);
data = mode7_scale[i] * sin(theta) >> 15;
writew(0x0250 + offset, data);
if(data) { data = ~data; }
writew(0x03b0 + offset, data);
offset += 2;
}
}
void ST010::op_08() {
int16 x0 = readw(0x0000);
int16 y0 = readw(0x0002);
int16 theta = readw(0x0004);
int16 x1, y1;
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
writew(0x0010, x1);
writew(0x0012, y1);
}
#endif

View File

@@ -0,0 +1,92 @@
#ifdef SUPERFX_CPP
SuperFXBus superfxbus;
namespace memory {
static SuperFXGSUROM gsurom;
static SuperFXGSURAM gsuram;
static SuperFXCPUROM fxrom;
static SuperFXCPURAM fxram;
};
void SuperFXBus::init() {
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapLinear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
map(MapLinear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0x60, 0x7d, 0x0000, 0xffff, memory::fxram);
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0xc0, 0xdf, 0x0000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0xe0, 0xff, 0x0000, 0xffff, memory::fxram);
}
//ROM / RAM access from the SuperFX CPU
unsigned SuperFXGSUROM::size() const {
return memory::cartrom.size();
}
uint8_t SuperFXGSUROM::read(unsigned addr) {
while(!superfx.regs.scmr.ron) superfx.add_clocks(2);
return memory::cartrom.read(addr);
}
void SuperFXGSUROM::write(unsigned addr, uint8_t data) {
}
unsigned SuperFXGSURAM::size() const {
return memory::cartram.size();
}
uint8_t SuperFXGSURAM::read(unsigned addr) {
while(!superfx.regs.scmr.ran) superfx.add_clocks(2);
return memory::cartram.read(addr);
}
void SuperFXGSURAM::write(unsigned addr, uint8_t data) {
while(!superfx.regs.scmr.ran) superfx.add_clocks(2);
memory::cartram.write(addr, data);
}
//ROM / RAM access from the S-CPU
unsigned SuperFXCPUROM::size() const {
return memory::cartrom.size();
}
uint8_t SuperFXCPUROM::read(unsigned addr) {
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
static const uint8_t data[16] = {
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
};
return data[addr & 15];
}
return memory::cartrom.read(addr);
}
void SuperFXCPUROM::write(unsigned addr, uint8_t data) {
memory::cartrom.write(addr, data);
}
unsigned SuperFXCPURAM::size() const {
return memory::cartram.size();
}
uint8_t SuperFXCPURAM::read(unsigned addr) {
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
return memory::cartram.read(addr);
}
void SuperFXCPURAM::write(unsigned addr, uint8_t data) {
memory::cartram.write(addr, data);
}
#endif

View File

@@ -0,0 +1,27 @@
struct SuperFXBus : Bus {
void init();
};
struct SuperFXGSUROM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXGSURAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXCPUROM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXCPURAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};

View File

@@ -0,0 +1,121 @@
#ifdef SUPERFX_CPP
#include "opcodes.cpp"
#include "opcode_table.cpp"
void SuperFX::exec_opcode() {
#if 0
if(!fp) fp = fopen("sfxtrace.log", "wb");
char t[4096];
disassemble_opcode(t);
fprintf(fp, "%s ", t);
for(unsigned i = 0; i < 16; i++) fprintf(fp, "r%u:%.4x ", i, (uint16_t)regs.r[i]);
fprintf(fp, "\n");
#endif
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
if(r15_modified == false) regs.r[15]++;
}
uint8_t SuperFX::color(uint8_t source) {
if(regs.por.highnibble) return (regs.colr & 0xf0) | (source >> 4);
if(regs.por.freezehigh) return (regs.colr & 0xf0) | (source & 0x0f);
return source;
}
void SuperFX::plot(uint8_t x, uint8_t y) {
uint8_t color = regs.colr;
if(regs.por.dither && regs.scmr.md != 3) {
if((x ^ y) & 1) color >>= 4;
color &= 0x0f;
}
if(!regs.por.transparent) {
if(regs.scmr.md == 3) {
if(regs.por.freezehigh) {
if((color & 0x0f) == 0) return;
} else {
if(color == 0) return;
}
} else {
if((color & 0x0f) == 0) return;
}
}
uint16_t offset = (y << 5) + (x >> 3);
if(offset != pixelcache[0].offset) {
pixelcache_flush(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
pixelcache[0].offset = offset;
}
x = (x & 7) ^ 7;
pixelcache[0].data[x] = color;
pixelcache[0].bitpend |= 1 << x;
if(pixelcache[0].bitpend == 0xff) {
pixelcache_flush(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
}
}
uint8_t SuperFX::rpix(uint8_t x, uint8_t y) {
pixelcache_flush(pixelcache[1]);
pixelcache_flush(pixelcache[0]);
unsigned cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
uint8_t data = 0x00;
x = (x & 7) ^ 7;
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
add_clocks(memory_access_speed);
data |= ((superfxbus.read(addr + byte) >> x) & 1) << n;
}
return data;
}
void SuperFX::pixelcache_flush(pixelcache_t &cache) {
if(cache.bitpend == 0x00) return;
uint8_t x = cache.offset << 3;
uint8_t y = cache.offset >> 5;
unsigned cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
uint8_t data = 0x00;
for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x;
if(cache.bitpend != 0xff) {
add_clocks(memory_access_speed);
data &= cache.bitpend;
data |= superfxbus.read(addr + byte) & ~cache.bitpend;
}
add_clocks(memory_access_speed);
superfxbus.write(addr + byte, data);
}
cache.bitpend = 0x00;
}
#endif

View File

@@ -0,0 +1,93 @@
#include "registers.hpp"
void exec_opcode();
uint8_t color(uint8_t source);
void plot(uint8_t x, uint8_t y);
uint8_t rpix(uint8_t x, uint8_t y);
void pixelcache_flush(pixelcache_t &cache);
void (SuperFX::*opcode_table[1024])();
void initialize_opcode_table();
//opcodes.cpp
template<int> void op_adc_i();
template<int> void op_adc_r();
template<int> void op_add_i();
template<int> void op_add_r();
void op_alt1();
void op_alt2();
void op_alt3();
template<int> void op_and_i();
template<int> void op_and_r();
void op_asr();
void op_bge();
void op_bcc();
void op_bcs();
void op_beq();
template<int> void op_bic_i();
template<int> void op_bic_r();
void op_blt();
void op_bmi();
void op_bne();
void op_bpl();
void op_bra();
void op_bvc();
void op_bvs();
void op_cache();
void op_cmode();
template<int> void op_cmp_r();
void op_color();
template<int> void op_dec_r();
void op_div2();
void op_fmult();
template<int> void op_from_r();
void op_getb();
void op_getbl();
void op_getbh();
void op_getbs();
void op_getc();
void op_hib();
template<int> void op_ibt_r();
template<int> void op_inc_r();
template<int> void op_iwt_r();
template<int> void op_jmp_r();
template<int> void op_ldb_ir();
template<int> void op_ldw_ir();
template<int> void op_link();
template<int> void op_ljmp_r();
template<int> void op_lm_r();
template<int> void op_lms_r();
void op_lmult();
void op_lob();
void op_loop();
void op_lsr();
void op_merge();
template<int> void op_mult_i();
template<int> void op_mult_r();
void op_nop();
void op_not();
template<int> void op_or_i();
template<int> void op_or_r();
void op_plot();
void op_ramb();
void op_rol();
void op_romb();
void op_ror();
void op_rpix();
template<int> void op_sbc_r();
void op_sbk();
void op_sex();
template<int> void op_sm_r();
template<int> void op_sms_r();
template<int> void op_stb_ir();
void op_stop();
template<int> void op_stw_ir();
template<int> void op_sub_i();
template<int> void op_sub_r();
void op_swap();
template<int> void op_to_r();
template<int> void op_umult_i();
template<int> void op_umult_r();
template<int> void op_with_r();
template<int> void op_xor_i();
template<int> void op_xor_r();

View File

@@ -0,0 +1,270 @@
#ifdef SUPERFX_CPP
void SuperFX::initialize_opcode_table() {
#define op4(id, name) \
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>)
#define op6(id, name) \
op(id+ 0, name< 8>) op(id+ 1, name< 9>) op(id+ 2, name<10>) op(id+ 3, name<11>) \
op(id+ 4, name<12>) op(id+ 5, name<13>)
#define op12(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>)
#define op15l(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>)
#define op15h(id, name) \
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>) \
op(id+ 4, name< 5>) op(id+ 5, name< 6>) op(id+ 6, name< 7>) op(id+ 7, name< 8>) \
op(id+ 8, name< 9>) op(id+ 9, name<10>) op(id+10, name<11>) op(id+11, name<12>) \
op(id+12, name<13>) op(id+13, name<14>) op(id+14, name<15>)
#define op16(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>) op(id+15, name<15>)
//======
// ALT0
//======
#define op(id, name) opcode_table[ 0 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stw_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldw_ir)
op (0x4c, plot)
op (0x4d, swap)
op (0x4e, color)
op (0x4f, not)
op16 (0x50, add_r)
op16 (0x60, sub_r)
op (0x70, merge)
op15h(0x71, and_r)
op16 (0x80, mult_r)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, asr)
op (0x97, ror)
op6 (0x98, jmp_r)
op (0x9e, lob)
op (0x9f, fmult)
op16 (0xa0, ibt_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, or_r)
op15l(0xd0, inc_r)
op (0xdf, getc)
op15l(0xe0, dec_r)
op (0xef, getb)
op16 (0xf0, iwt_r)
#undef op
//======
// ALT1
//======
#define op(id, name) opcode_table[256 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stb_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldb_ir)
op (0x4c, rpix)
op (0x4d, swap)
op (0x4e, cmode)
op (0x4f, not)
op16 (0x50, adc_r)
op16 (0x60, sbc_r)
op (0x70, merge)
op15h(0x71, bic_r)
op16 (0x80, umult_r)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, div2)
op (0x97, ror)
op6 (0x98, ljmp_r)
op (0x9e, lob)
op (0x9f, lmult)
op16 (0xa0, lms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, xor_r)
op15l(0xd0, inc_r)
op (0xdf, getc)
op15l(0xe0, dec_r)
op (0xef, getbh)
op16 (0xf0, lm_r)
#undef op
//======
// ALT2
//======
#define op(id, name) opcode_table[512 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stw_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldw_ir)
op (0x4c, plot)
op (0x4d, swap)
op (0x4e, color)
op (0x4f, not)
op16 (0x50, add_i)
op16 (0x60, sub_i)
op (0x70, merge)
op15h(0x71, and_i)
op16 (0x80, mult_i)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, asr)
op (0x97, ror)
op6 (0x98, jmp_r)
op (0x9e, lob)
op (0x9f, fmult)
op16 (0xa0, sms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, or_i)
op15l(0xd0, inc_r)
op (0xdf, ramb)
op15l(0xe0, dec_r)
op (0xef, getbl)
op16 (0xf0, sm_r)
#undef op
//======
// ALT3
//======
#define op(id, name) opcode_table[768 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stb_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldb_ir)
op (0x4c, rpix)
op (0x4d, swap)
op (0x4e, cmode)
op (0x4f, not)
op16 (0x50, adc_i)
op16 (0x60, cmp_r)
op (0x70, merge)
op15h(0x71, bic_i)
op16 (0x80, umult_i)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, div2)
op (0x97, ror)
op6 (0x98, ljmp_r)
op (0x9e, lob)
op (0x9f, lmult)
op16 (0xa0, lms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, xor_i)
op15l(0xd0, inc_r)
op (0xdf, romb)
op15l(0xe0, dec_r)
op (0xef, getbs)
op16 (0xf0, lm_r)
#undef op
#undef op4
#undef op6
#undef op12
#undef op15l
#undef op15h
#undef op16
}
#endif

View File

@@ -0,0 +1,661 @@
#ifdef SUPERFX_CPP
//$00 stop
void SuperFX::op_stop() {
if(regs.cfgr.irq == 0) {
regs.sfr.irq = 1;
cpu.regs.irq = 1;
}
regs.sfr.g = 0;
regs.pipeline = 0x01;
regs.reset();
}
//$01 nop
void SuperFX::op_nop() {
regs.reset();
}
//$02 cache
void SuperFX::op_cache() {
if(regs.cbr != (regs.r[15] & 0xfff0)) {
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
}
regs.reset();
}
//$03 lsr
void SuperFX::op_lsr() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = regs.sr() >> 1;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$04 rol
void SuperFX::op_rol() {
bool carry = (regs.sr() & 0x8000);
regs.dr() = (regs.sr() << 1) | regs.sfr.cy;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = carry;
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$05 bra e
void SuperFX::op_bra() {
regs.r[15] += (int8_t)pipe();
}
//$06 blt e
void SuperFX::op_blt() {
int e = (int8_t)pipe();
if((regs.sfr.s ^ regs.sfr.ov) == 0) regs.r[15] += e;
}
//$07 bge e
void SuperFX::op_bge() {
int e = (int8_t)pipe();
if((regs.sfr.s ^ regs.sfr.ov) == 1) regs.r[15] += e;
}
//$08 bne e
void SuperFX::op_bne() {
int e = (int8_t)pipe();
if(regs.sfr.z == 0) regs.r[15] += e;
}
//$09 beq e
void SuperFX::op_beq() {
int e = (int8_t)pipe();
if(regs.sfr.z == 1) regs.r[15] += e;
}
//$0a bpl e
void SuperFX::op_bpl() {
int e = (int8_t)pipe();
if(regs.sfr.s == 0) regs.r[15] += e;
}
//$0b bmi e
void SuperFX::op_bmi() {
int e = (int8_t)pipe();
if(regs.sfr.s == 1) regs.r[15] += e;
}
//$0c bcc e
void SuperFX::op_bcc() {
int e = (int8_t)pipe();
if(regs.sfr.cy == 0) regs.r[15] += e;
}
//$0d bcs e
void SuperFX::op_bcs() {
int e = (int8_t)pipe();
if(regs.sfr.cy == 1) regs.r[15] += e;
}
//$0e bvc e
void SuperFX::op_bvc() {
int e = (int8_t)pipe();
if(regs.sfr.ov == 0) regs.r[15] += e;
}
//$0f bvs e
void SuperFX::op_bvs() {
int e = (int8_t)pipe();
if(regs.sfr.ov == 1) regs.r[15] += e;
}
//$10-1f(b0): to rN
//$10-1f(b1): move rN
template<int n> void SuperFX::op_to_r() {
if(regs.sfr.b == 0) {
regs.dreg = &regs.r[n];
} else {
regs.r[n] = regs.sr();
regs.reset();
}
}
//$20-2f: with rN
template<int n> void SuperFX::op_with_r() {
regs.sreg = &regs.r[n];
regs.dreg = &regs.r[n];
regs.sfr.b = 1;
}
//$30-3b(alt0): stw (rN)
template<int n> void SuperFX::op_stw_ir() {
regs.ramaddr = regs.r[n];
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
//$30-3b(alt1): stb (rN)
template<int n> void SuperFX::op_stb_ir() {
regs.ramaddr = regs.r[n];
rambuffer_write(regs.ramaddr, regs.sr());
regs.reset();
}
//$3c loop
void SuperFX::op_loop() {
regs.r[12]--;
regs.sfr.s = (regs.r[12] & 0x8000);
regs.sfr.z = (regs.r[12] == 0);
if(!regs.sfr.z) regs.r[15] = regs.r[13];
regs.reset();
}
//$3d alt1
void SuperFX::op_alt1() {
regs.sfr.b = 0;
regs.sfr.alt1 = 1;
}
//$3e alt2
void SuperFX::op_alt2() {
regs.sfr.b = 0;
regs.sfr.alt2 = 1;
}
//$3f alt3
void SuperFX::op_alt3() {
regs.sfr.b = 0;
regs.sfr.alt1 = 1;
regs.sfr.alt2 = 1;
}
//$40-4b(alt0): ldw (rN)
template<int n> void SuperFX::op_ldw_ir() {
regs.ramaddr = regs.r[n];
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.dr() = data;
regs.reset();
}
//$40-4b(alt1): ldb (rN)
template<int n> void SuperFX::op_ldb_ir() {
regs.ramaddr = regs.r[n];
regs.dr() = rambuffer_read(regs.ramaddr);
regs.reset();
}
//$4c(alt0): plot
void SuperFX::op_plot() {
plot(regs.r[1], regs.r[2]);
regs.r[1]++;
regs.reset();
}
//$4c(alt1): rpix
void SuperFX::op_rpix() {
regs.dr() = rpix(regs.r[1], regs.r[2]);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$4d: swap
void SuperFX::op_swap() {
regs.dr() = (regs.sr() >> 8) | (regs.sr() << 8);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$4e(alt0): color
void SuperFX::op_color() {
regs.colr = color(regs.sr());
regs.reset();
}
//$4e(alt1): cmode
void SuperFX::op_cmode() {
regs.por = regs.sr();
regs.reset();
}
//$4f: not
void SuperFX::op_not() {
regs.dr() = ~regs.sr();
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$50-5f(alt0): add rN
template<int n> void SuperFX::op_add_r() {
int r = regs.sr() + regs.r[n];
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt1): adc rN
template<int n> void SuperFX::op_adc_r() {
int r = regs.sr() + regs.r[n] + regs.sfr.cy;
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt2): add #N
template<int n> void SuperFX::op_add_i() {
int r = regs.sr() + n;
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt3): adc #N
template<int n> void SuperFX::op_adc_i() {
int r = regs.sr() + n + regs.sfr.cy;
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt0): sub rN
template<int n> void SuperFX::op_sub_r() {
int r = regs.sr() - regs.r[n];
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt1): sbc rN
template<int n> void SuperFX::op_sbc_r() {
int r = regs.sr() - regs.r[n] - !regs.sfr.cy;
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt2): sub #N
template<int n> void SuperFX::op_sub_i() {
int r = regs.sr() - n;
regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt3): cmp rN
template<int n> void SuperFX::op_cmp_r() {
int r = regs.sr() - regs.r[n];
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.reset();
}
//$70: merge
void SuperFX::op_merge() {
regs.dr() = (regs.r[7] & 0xff00) | (regs.r[8] >> 8);
regs.sfr.ov = (regs.dr() & 0xc0c0);
regs.sfr.s = (regs.dr() & 0x8080);
regs.sfr.cy = (regs.dr() & 0xe0e0);
regs.sfr.z = (regs.dr() & 0xf0f0);
regs.reset();
}
//$71-7f(alt0): and rN
template<int n> void SuperFX::op_and_r() {
regs.dr() = regs.sr() & regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt1): bic rN
template<int n> void SuperFX::op_bic_r() {
regs.dr() = regs.sr() & ~regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt2): and #N
template<int n> void SuperFX::op_and_i() {
regs.dr() = regs.sr() & n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt3): bic #N
template<int n> void SuperFX::op_bic_i() {
regs.dr() = regs.sr() & ~n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$80-8f(alt0): mult rN
template<int n> void SuperFX::op_mult_r() {
regs.dr() = (int8_t)regs.sr() * (int8_t)regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt1): umult rN
template<int n> void SuperFX::op_umult_r() {
regs.dr() = (uint8_t)regs.sr() * (uint8_t)regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt2): mult #N
template<int n> void SuperFX::op_mult_i() {
regs.dr() = (int8_t)regs.sr() * (int8_t)n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt3): umult #N
template<int n> void SuperFX::op_umult_i() {
regs.dr() = (uint8_t)regs.sr() * (uint8_t)n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$90: sbk
void SuperFX::op_sbk() {
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
//$91-94: link #N
template<int n> void SuperFX::op_link() {
regs.r[11] = regs.r[15] + n;
regs.reset();
}
//$95: sex
void SuperFX::op_sex() {
regs.dr() = (int8_t)regs.sr();
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$96(alt0): asr
void SuperFX::op_asr() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = (int16_t)regs.sr() >> 1;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$96(alt1): div2
void SuperFX::op_div2() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = ((int16_t)regs.sr() >> 1) + ((regs.sr() + 1) >> 16);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$97: ror
void SuperFX::op_ror() {
bool carry = (regs.sr() & 1);
regs.dr() = (regs.sfr.cy << 15) | (regs.sr() >> 1);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = carry;
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$98-9d(alt0): jmp rN
template<int n> void SuperFX::op_jmp_r() {
regs.r[15] = regs.r[n];
regs.reset();
}
//$98-9d(alt1): ljmp rN
template<int n> void SuperFX::op_ljmp_r() {
regs.pbr = regs.r[n];
regs.r[15] = regs.sr();
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
regs.reset();
}
//$9e: lob
void SuperFX::op_lob() {
regs.dr() = regs.sr() & 0xff;
regs.sfr.s = (regs.dr() & 0x80);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$9f(alt0): fmult
void SuperFX::op_fmult() {
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
regs.dr() = result >> 16;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = (result & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
add_clocks(4 + (regs.cfgr.ms0 << 2));
}
//$9f(alt1): lmult
void SuperFX::op_lmult() {
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
regs.r[4] = result;
regs.dr() = result >> 16;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = (result & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
add_clocks(4 + (regs.cfgr.ms0 << 2));
}
//$a0-af(alt0): ibt rN,#pp
template<int n> void SuperFX::op_ibt_r() {
regs.r[n] = (int8_t)pipe();
regs.reset();
}
//$a0-af(alt1): lms rN,(yy)
template<int n> void SuperFX::op_lms_r() {
regs.ramaddr = pipe() << 1;
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.r[n] = data;
regs.reset();
}
//$a0-af(alt2): sms (yy),rN
template<int n> void SuperFX::op_sms_r() {
regs.ramaddr = pipe() << 1;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
regs.reset();
}
//$b0-bf(b0): from rN
//$b0-bf(b1): moves rN
template<int n> void SuperFX::op_from_r() {
if(regs.sfr.b == 0) {
regs.sreg = &regs.r[n];
} else {
regs.dr() = regs.r[n];
regs.sfr.ov = (regs.dr() & 0x80);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
}
//$c0: hib
void SuperFX::op_hib() {
regs.dr() = regs.sr() >> 8;
regs.sfr.s = (regs.dr() & 0x80);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt0): or rN
template<int n> void SuperFX::op_or_r() {
regs.dr() = regs.sr() | regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt1): xor rN
template<int n> void SuperFX::op_xor_r() {
regs.dr() = regs.sr() ^ regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt2): or #N
template<int n> void SuperFX::op_or_i() {
regs.dr() = regs.sr() | n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt3): xor #N
template<int n> void SuperFX::op_xor_i() {
regs.dr() = regs.sr() ^ n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$d0-de: inc rN
template<int n> void SuperFX::op_inc_r() {
regs.r[n]++;
regs.sfr.s = (regs.r[n] & 0x8000);
regs.sfr.z = (regs.r[n] == 0);
regs.reset();
}
//$df(alt0): getc
void SuperFX::op_getc() {
regs.colr = color(rombuffer_read());
regs.reset();
}
//$df(alt2): ramb
void SuperFX::op_ramb() {
rambuffer_sync();
regs.rambr = regs.sr();
regs.reset();
}
//$df(alt3): romb
void SuperFX::op_romb() {
rombuffer_sync();
regs.rombr = regs.sr();
regs.reset();
}
//$e0-ee: dec rN
template<int n> void SuperFX::op_dec_r() {
regs.r[n]--;
regs.sfr.s = (regs.r[n] & 0x8000);
regs.sfr.z = (regs.r[n] == 0);
regs.reset();
}
//$ef(alt0): getb
void SuperFX::op_getb() {
regs.dr() = rombuffer_read();
regs.reset();
}
//$ef(alt1): getbh
void SuperFX::op_getbh() {
regs.dr() = (rombuffer_read() << 8) | (regs.sr() & 0x00ff);
regs.reset();
}
//$ef(alt2): getbl
void SuperFX::op_getbl() {
regs.dr() = (regs.sr() & 0xff00) | (rombuffer_read() << 0);
regs.reset();
}
//$ef(alt3): getbs
void SuperFX::op_getbs() {
regs.dr() = (int8_t)rombuffer_read();
regs.reset();
}
//$f0-ff(alt0): iwt rN,#xx
template<int n> void SuperFX::op_iwt_r() {
uint16_t data;
data = pipe() << 0;
data |= pipe() << 8;
regs.r[n] = data;
regs.reset();
}
//$f0-ff(alt1): lm rN,(xx)
template<int n> void SuperFX::op_lm_r() {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.r[n] = data;
regs.reset();
}
//$f0-ff(alt2): sm (xx),rN
template<int n> void SuperFX::op_sm_r() {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
regs.reset();
}
#endif

View File

@@ -0,0 +1,177 @@
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
struct reg16_t : noncopyable {
uint16_t data;
function<void (uint16_t)> on_modify;
inline operator unsigned() const { return data; }
inline uint16_t assign(uint16_t i) {
if(on_modify) on_modify(i);
else data = i;
return data;
}
inline unsigned operator++() { return assign(data + 1); }
inline unsigned operator--() { return assign(data - 1); }
inline unsigned operator++(int) { unsigned r = data; assign(data + 1); return r; }
inline unsigned operator--(int) { unsigned r = data; assign(data - 1); return r; }
inline unsigned operator = (unsigned i) { return assign(i); }
inline unsigned operator |= (unsigned i) { return assign(data | i); }
inline unsigned operator ^= (unsigned i) { return assign(data ^ i); }
inline unsigned operator &= (unsigned i) { return assign(data & i); }
inline unsigned operator <<= (unsigned i) { return assign(data << i); }
inline unsigned operator >>= (unsigned i) { return assign(data >> i); }
inline unsigned operator += (unsigned i) { return assign(data + i); }
inline unsigned operator -= (unsigned i) { return assign(data - i); }
inline unsigned operator *= (unsigned i) { return assign(data * i); }
inline unsigned operator /= (unsigned i) { return assign(data / i); }
inline unsigned operator %= (unsigned i) { return assign(data % i); }
inline unsigned operator = (const reg16_t& i) { return assign(i); }
reg16_t() : data(0) {}
};
struct sfr_t {
bool irq; //interrupt flag
bool b; //WITH flag
bool ih; //immediate higher 8-bit flag
bool il; //immediate lower 8-bit flag
bool alt2; //ALT2 mode
bool alt1; //ALT2 instruction mode
bool r; //ROM r14 read flag
bool g; //GO flag
bool ov; //overflow flag
bool s; //sign flag
bool cy; //carry flag
bool z; //zero flag
operator uint16_t() const {
return (irq << 15) | (b << 12) | (ih << 11) | (il << 10) | (alt2 << 9) | (alt1 << 8)
| (r << 6) | (g << 5) | (ov << 4) | (s << 3) | (cy << 2) | (z << 1);
}
sfr_t& operator=(uint16_t data) {
irq = data & 0x8000;
b = data & 0x1000;
ih = data & 0x0800;
il = data & 0x0400;
alt2 = data & 0x0200;
alt1 = data & 0x0100;
r = data & 0x0040;
g = data & 0x0020;
ov = data & 0x0010;
s = data & 0x0008;
cy = data & 0x0004;
z = data & 0x0002;
return *this;
}
};
struct scmr_t {
unsigned ht;
bool ron;
bool ran;
unsigned md;
operator uint8_t() const {
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
}
scmr_t& operator=(uint8_t data) {
ht = (bool)(data & 0x20) << 1;
ht |= (bool)(data & 0x04) << 0;
ron = data & 0x10;
ran = data & 0x08;
md = data & 0x03;
return *this;
}
};
struct por_t {
bool obj;
bool freezehigh;
bool highnibble;
bool dither;
bool transparent;
operator uint8_t() const {
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
}
por_t& operator=(uint8_t data) {
obj = data & 0x10;
freezehigh = data & 0x08;
highnibble = data & 0x04;
dither = data & 0x02;
transparent = data & 0x01;
return *this;
}
};
struct cfgr_t {
bool irq;
bool ms0;
operator uint8_t() const {
return (irq << 7) | (ms0 << 5);
}
cfgr_t& operator=(uint8_t data) {
irq = data & 0x80;
ms0 = data & 0x20;
return *this;
}
};
struct regs_t {
uint8_t pipeline;
uint16_t ramaddr;
reg16_t r[16]; //general purpose registers
sfr_t sfr; //status flag register
uint8_t pbr; //program bank register
uint8_t rombr; //game pack ROM bank register
bool rambr; //game pack RAM bank register
uint16_t cbr; //cache base register
uint8_t scbr; //screen base register
scmr_t scmr; //screen mode register
uint8_t colr; //color register
por_t por; //plot option register
bool bramr; //back-up RAM register
uint8_t vcr; //version code register
cfgr_t cfgr; //config register
bool clsr; //clock select register
unsigned romcl; //clock ticks until romdr is valid
uint8_t romdr; //ROM buffer data register
unsigned ramcl; //clock ticks until ramdr is valid
uint16_t ramar; //RAM buffer address register
uint8_t ramdr; //RAM buffer data register
reg16_t *sreg, *dreg;
reg16_t& sr() { return *sreg; } //source register (from)
reg16_t& dr() { return *dreg; } //destination register (to)
void reset() {
sfr.b = 0;
sfr.alt1 = 0;
sfr.alt2 = 0;
sreg = &r[0];
dreg = &r[0];
}
} regs;
struct cache_t {
uint8_t buffer[512];
bool valid[32];
} cache;
struct pixelcache_t {
uint16_t offset;
uint8_t bitpend;
uint8_t data[8];
} pixelcache[2];

View File

@@ -0,0 +1,275 @@
void SuperFX::disassemble_opcode(char *output) {
*output = 0;
if(!regs.sfr.alt2) {
if(!regs.sfr.alt1) {
disassemble_alt0(output);
} else {
disassemble_alt1(output);
}
} else {
if(!regs.sfr.alt1) {
disassemble_alt2(output);
} else {
disassemble_alt3(output);
}
}
unsigned length = strlen(output);
while(length++ < 20) strcat(output, " ");
}
#define case4(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3
#define case6(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5
#define case12(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11
#define case15(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14
#define case16(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
#define op0 regs.pipeline
#define op1 superfxbus.read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 superfxbus.read((regs.pbr << 16) + regs.r[15] + 1)
void SuperFX::disassemble_alt0(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and r%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "ibt r%u,#$%.2x", op0 & 15, op1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib");
case15(0xc1): sprintf(t, "or r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getb"); break;
case16(0xf0): sprintf(t, "iwt r%u,#$%.2x%.2x", op0 & 15, op2, op1); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt1(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sbc r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic r%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbh"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt2(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add #%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub #%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and #%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "or #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "ramb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbl"); break;
case16(0xf0): sprintf(t, "sm r%u", op0 & 15); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt3(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc #%u", op0 & 15); break;
case16(0x60): sprintf(t, "cmp r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic #%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u", op0 & 15); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "romb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbs"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
#undef case4
#undef case6
#undef case12
#undef case15
#undef case16
#undef op0
#undef op1
#undef op2

View File

@@ -0,0 +1,5 @@
void disassemble_opcode(char *output);
void disassemble_alt0(char *output);
void disassemble_alt1(char *output);
void disassemble_alt2(char *output);
void disassemble_alt3(char *output);

View File

@@ -0,0 +1,67 @@
uint8_t SuperFX::op_read(uint16_t addr) {
uint16_t offset = addr - regs.cbr;
if(offset < 512) {
if(cache.valid[offset >> 4] == false) {
unsigned dp = offset & 0xfff0;
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
for(unsigned n = 0; n < 16; n++) {
add_clocks(memory_access_speed);
cache.buffer[dp++] = superfxbus.read(sp++);
}
cache.valid[offset >> 4] = true;
} else {
add_clocks(cache_access_speed);
}
return cache.buffer[offset];
}
if(regs.pbr <= 0x5f) {
//$[00-5f]:[0000-ffff] ROM
rombuffer_sync();
add_clocks(memory_access_speed);
return superfxbus.read((regs.pbr << 16) + addr);
} else {
//$[60-7f]:[0000-ffff] RAM
rambuffer_sync();
add_clocks(memory_access_speed);
return superfxbus.read((regs.pbr << 16) + addr);
}
}
uint8_t SuperFX::peekpipe() {
uint8_t result = regs.pipeline;
regs.pipeline = op_read(regs.r[15]);
r15_modified = false;
return result;
}
uint8_t SuperFX::pipe() {
uint8_t result = regs.pipeline;
regs.pipeline = op_read(++regs.r[15]);
r15_modified = false;
return result;
}
void SuperFX::cache_flush() {
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
}
uint8_t SuperFX::cache_mmio_read(uint16_t addr) {
addr = (addr + regs.cbr) & 511;
return cache.buffer[addr];
}
void SuperFX::cache_mmio_write(uint16_t addr, uint8_t data) {
addr = (addr + regs.cbr) & 511;
cache.buffer[addr] = data;
if((addr & 15) == 15) cache.valid[addr >> 4] = true;
}
void SuperFX::memory_reset() {
for(unsigned n = 0; n < 512; n++) cache.buffer[n] = 0x00;
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
for(unsigned n = 0; n < 2; n++) {
pixelcache[n].offset = ~0;
pixelcache[n].bitpend = 0x00;
}
}

View File

@@ -0,0 +1,9 @@
uint8_t op_read(uint16_t addr);
alwaysinline uint8_t peekpipe();
alwaysinline uint8_t pipe();
void cache_flush();
uint8_t cache_mmio_read(uint16_t addr);
void cache_mmio_write(uint16_t addr, uint8_t data);
void memory_reset();

View File

@@ -0,0 +1,118 @@
#ifdef SUPERFX_CPP
uint8_t SuperFX::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_read(addr - 0x3100);
}
if(addr >= 0x3000 && addr <= 0x301f) {
return regs.r[(addr >> 1) & 15] >> ((addr & 1) << 3);
}
switch(addr) {
case 0x3030: {
return regs.sfr >> 0;
}
case 0x3031: {
uint8_t r = regs.sfr >> 8;
regs.sfr.irq = 0;
cpu.regs.irq = 0;
return r;
}
case 0x3034: {
return regs.pbr;
}
case 0x3036: {
return regs.rombr;
}
case 0x303b: {
return regs.vcr;
}
case 0x303c: {
return regs.rambr;
}
case 0x303e: {
return regs.cbr >> 0;
}
case 0x303f: {
return regs.cbr >> 8;
}
}
return 0x00;
}
void SuperFX::mmio_write(unsigned addr, uint8_t data) {
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_write(addr - 0x3100, data);
}
if(addr >= 0x3000 && addr <= 0x301f) {
unsigned n = (addr >> 1) & 15;
if((addr & 1) == 0) {
regs.r[n] = (regs.r[n] & 0xff00) | data;
} else {
regs.r[n] = (data << 8) | (regs.r[n] & 0xff);
}
if(addr == 0x301f) regs.sfr.g = 1;
return;
}
switch(addr) {
case 0x3030: {
bool g = regs.sfr.g;
regs.sfr = (regs.sfr & 0xff00) | (data << 0);
if(g == 1 && regs.sfr.g == 0) {
regs.cbr = 0x0000;
cache_flush();
}
} break;
case 0x3031: {
regs.sfr = (data << 8) | (regs.sfr & 0x00ff);
} break;
case 0x3033: {
regs.bramr = data;
} break;
case 0x3034: {
regs.pbr = data;
cache_flush();
} break;
case 0x3037: {
regs.cfgr = data;
if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
} break;
case 0x3038: {
regs.scbr = data;
} break;
case 0x3039: {
regs.clsr = data;
if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
cache_access_speed = (regs.clsr ? config.superfx.fast_cache_speed : config.superfx.slow_cache_speed );
memory_access_speed = (regs.clsr ? config.superfx.fast_memory_speed : config.superfx.slow_memory_speed);
} break;
case 0x303a: {
regs.scmr = data;
} break;
}
}
#endif

View File

@@ -0,0 +1,2 @@
uint8_t mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8_t data);

View File

@@ -0,0 +1,61 @@
#include <../base.hpp>
#define SUPERFX_CPP
namespace SNES {
#include "bus/bus.cpp"
#include "core/core.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
#include "disasm/disasm.cpp"
SuperFX superfx;
void SuperFX::enter() {
while(true) {
while(regs.sfr.g == 0) add_clocks(2);
exec_opcode();
}
}
void SuperFX::init() {
initialize_opcode_table();
regs.r[14].on_modify = bind(&SuperFX::r14_modify, this);
regs.r[15].on_modify = bind(&SuperFX::r15_modify, this);
}
void SuperFX::enable() {
for(uint16_t i = 0x3000; i <= 0x32ff; i++) memory::mmio.map(i, *this);
}
void SuperFX::power() {
reset();
}
void SuperFX::reset() {
superfxbus.init();
for(unsigned n = 0; n < 16; n++) regs.r[n] = 0x0000;
regs.sfr = 0x0000;
regs.pbr = 0x00;
regs.rombr = 0x00;
regs.rambr = 0;
regs.cbr = 0x0000;
regs.scbr = 0x00;
regs.scmr = 0x00;
regs.colr = 0x00;
regs.por = 0x00;
regs.bramr = 0;
regs.vcr = 0x04;
regs.cfgr = 0x00;
regs.clsr = 0;
regs.pipeline = 0x01; //nop
regs.ramaddr = 0x0000;
regs.reset();
memory_reset();
timing_reset();
}
};

View File

@@ -0,0 +1,20 @@
#include "bus/bus.hpp"
class SuperFX : public MMIO {
public:
#include "core/core.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
#include "disasm/disasm.hpp"
void enter();
void init();
void enable();
void power();
void reset();
};
extern SuperFX superfx;
extern SuperFXBus superfxbus;

View File

@@ -0,0 +1,72 @@
void SuperFX::add_clocks(unsigned clocks) {
if(regs.romcl) {
regs.romcl -= min(clocks, regs.romcl);
if(regs.romcl == 0) {
regs.sfr.r = 0;
regs.romdr = superfxbus.read((regs.rombr << 16) + regs.r[14]);
}
}
if(regs.ramcl) {
regs.ramcl -= min(clocks, regs.ramcl);
if(regs.ramcl == 0) {
superfxbus.write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
}
}
scheduler.addclocks_cop(clocks);
scheduler.sync_copcpu();
}
void SuperFX::rombuffer_sync() {
if(regs.romcl) add_clocks(regs.romcl);
}
void SuperFX::rombuffer_update() {
regs.sfr.r = 1;
regs.romcl = memory_access_speed;
}
uint8_t SuperFX::rombuffer_read() {
rombuffer_sync();
return regs.romdr;
}
void SuperFX::rambuffer_sync() {
if(regs.ramcl) add_clocks(regs.ramcl);
}
uint8_t SuperFX::rambuffer_read(uint16_t addr) {
rambuffer_sync();
return superfxbus.read(0x700000 + (regs.rambr << 16) + addr);
}
void SuperFX::rambuffer_write(uint16_t addr, uint8_t data) {
rambuffer_sync();
regs.ramcl = memory_access_speed;
regs.ramar = addr;
regs.ramdr = data;
}
void SuperFX::r14_modify(uint16_t data) {
regs.r[14].data = data;
rombuffer_update();
}
void SuperFX::r15_modify(uint16_t data) {
regs.r[15].data = data;
r15_modified = true;
}
void SuperFX::timing_reset() {
cache_access_speed = config.superfx.slow_cache_speed;
memory_access_speed = config.superfx.slow_memory_speed;
r15_modified = false;
regs.romcl = 0;
regs.romdr = 0;
regs.ramcl = 0;
regs.ramar = 0;
regs.ramdr = 0;
}

View File

@@ -0,0 +1,18 @@
unsigned cache_access_speed;
unsigned memory_access_speed;
bool r15_modified;
void add_clocks(unsigned clocks);
void rombuffer_sync();
void rombuffer_update();
uint8_t rombuffer_read();
void rambuffer_sync();
uint8_t rambuffer_read(uint16_t addr);
void rambuffer_write(uint16_t addr, uint8_t data);
void r14_modify(uint16_t);
void r15_modify(uint16_t);
void timing_reset();

View File

@@ -1 +1 @@
@mingw32-make platform=win compiler=mingw32-gcc clean
@mingw32-make clean

View File

@@ -1 +0,0 @@
make platform=x compiler=gcc clean

View File

@@ -1,5 +1,8 @@
#include <../base.hpp>
#define CPUCORE_CPP
namespace SNES {
#include "opcode_algorithms.cpp"
#include "opcode_functions.cpp"
#include "opcode_tables.cpp"
@@ -43,3 +46,5 @@ alwaysinline void CPUcore::op_io_cond6(uint16 addr) {
CPUcore::CPUcore() {
initialize_opcode_table();
}
};

View File

@@ -1,365 +1,369 @@
inline void CPUcore::op_adc_b() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += (rd.l & 15) + regs.p.c;
if(n0 > 9) {
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | n0;
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = r > 0xff;
}
regs.p.n = r & 0x80;
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void CPUcore::op_adc_w() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += (rd.w & 15) + regs.p.c;
if(n0 > 9) {
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 = (n2 - 10) & 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 = (n3 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | n0;
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = r > 0xffff;
}
regs.p.n = r & 0x8000;
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
inline void CPUcore::op_and_b() {
regs.a.l &= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_and_w() {
regs.a.w &= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_bit_b() {
regs.p.n = rd.l & 0x80;
regs.p.v = rd.l & 0x40;
regs.p.z = (rd.l & regs.a.l) == 0;
}
inline void CPUcore::op_bit_w() {
regs.p.n = rd.w & 0x8000;
regs.p.v = rd.w & 0x4000;
regs.p.z = (rd.w & regs.a.w) == 0;
}
inline void CPUcore::op_cmp_b() {
int r = regs.a.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cmp_w() {
int r = regs.a.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpx_b() {
int r = regs.x.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpx_w() {
int r = regs.x.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpy_b() {
int r = regs.y.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpy_w() {
int r = regs.y.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_eor_b() {
regs.a.l ^= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_eor_w() {
regs.a.w ^= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_lda_b() {
regs.a.l = rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_lda_w() {
regs.a.w = rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_ldx_b() {
regs.x.l = rd.l;
regs.p.n = regs.x.l & 0x80;
regs.p.z = regs.x.l == 0;
}
inline void CPUcore::op_ldx_w() {
regs.x.w = rd.w;
regs.p.n = regs.x.w & 0x8000;
regs.p.z = regs.x.w == 0;
}
inline void CPUcore::op_ldy_b() {
regs.y.l = rd.l;
regs.p.n = regs.y.l & 0x80;
regs.p.z = regs.y.l == 0;
}
inline void CPUcore::op_ldy_w() {
regs.y.w = rd.w;
regs.p.n = regs.y.w & 0x8000;
regs.p.z = regs.y.w == 0;
}
inline void CPUcore::op_ora_b() {
regs.a.l |= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_ora_w() {
regs.a.w |= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_sbc_b() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = r >= 0;
}
regs.p.n = r & 0x80;
regs.p.v = (regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void CPUcore::op_sbc_w() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
n3 -= ((rd.w >> 12) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
n2--;
}
if(n2 > 9) {
n2 += 10;
n3--;
}
if(n3 > 9) {
n3 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = r >= 0;
}
regs.p.n = r & 0x8000;
regs.p.v = (regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
inline void CPUcore::op_inc_b() {
rd.l++;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_inc_w() {
rd.w++;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_dec_b() {
rd.l--;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_dec_w() {
rd.w--;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_asl_b() {
regs.p.c = rd.l & 0x80;
rd.l <<= 1;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_asl_w() {
regs.p.c = rd.w & 0x8000;
rd.w <<= 1;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_lsr_b() {
regs.p.c = rd.l & 1;
rd.l >>= 1;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_lsr_w() {
regs.p.c = rd.w & 1;
rd.w >>= 1;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_rol_b() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.l & 0x80;
rd.l = (rd.l << 1) | carry;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_rol_w() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.w & 0x8000;
rd.w = (rd.w << 1) | carry;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_ror_b() {
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = rd.l & 1;
rd.l = carry | (rd.l >> 1);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_ror_w() {
unsigned carry = (unsigned)regs.p.c << 15;
regs.p.c = rd.w & 1;
rd.w = carry | (rd.w >> 1);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_trb_b() {
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l &= ~regs.a.l;
}
inline void CPUcore::op_trb_w() {
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w &= ~regs.a.w;
}
inline void CPUcore::op_tsb_b() {
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l |= regs.a.l;
}
inline void CPUcore::op_tsb_w() {
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w |= regs.a.w;
}
#ifdef CPUCORE_CPP
inline void CPUcore::op_adc_b() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 += (rd.l & 15) + regs.p.c;
if(n0 > 9) {
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.l >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n1 << 4) | n0;
} else {
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = r > 0xff;
}
regs.p.n = r & 0x80;
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void CPUcore::op_adc_w() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 += (rd.w & 15) + regs.p.c;
if(n0 > 9) {
n0 = (n0 - 10) & 15;
n1++;
}
n1 += ((rd.w >> 4) & 15);
if(n1 > 9) {
n1 = (n1 - 10) & 15;
n2++;
}
n2 += ((rd.w >> 8) & 15);
if(n2 > 9) {
n2 = (n2 - 10) & 15;
n3++;
}
n3 += ((rd.w >> 12) & 15);
if(n3 > 9) {
n3 = (n3 - 10) & 15;
regs.p.c = 1;
} else {
regs.p.c = 0;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | n0;
} else {
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = r > 0xffff;
}
regs.p.n = r & 0x8000;
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
inline void CPUcore::op_and_b() {
regs.a.l &= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_and_w() {
regs.a.w &= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_bit_b() {
regs.p.n = rd.l & 0x80;
regs.p.v = rd.l & 0x40;
regs.p.z = (rd.l & regs.a.l) == 0;
}
inline void CPUcore::op_bit_w() {
regs.p.n = rd.w & 0x8000;
regs.p.v = rd.w & 0x4000;
regs.p.z = (rd.w & regs.a.w) == 0;
}
inline void CPUcore::op_cmp_b() {
int r = regs.a.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cmp_w() {
int r = regs.a.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpx_b() {
int r = regs.x.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpx_w() {
int r = regs.x.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpy_b() {
int r = regs.y.l - rd.l;
regs.p.n = r & 0x80;
regs.p.z = (uint8)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_cpy_w() {
int r = regs.y.w - rd.w;
regs.p.n = r & 0x8000;
regs.p.z = (uint16)r == 0;
regs.p.c = r >= 0;
}
inline void CPUcore::op_eor_b() {
regs.a.l ^= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_eor_w() {
regs.a.w ^= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_lda_b() {
regs.a.l = rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_lda_w() {
regs.a.w = rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_ldx_b() {
regs.x.l = rd.l;
regs.p.n = regs.x.l & 0x80;
regs.p.z = regs.x.l == 0;
}
inline void CPUcore::op_ldx_w() {
regs.x.w = rd.w;
regs.p.n = regs.x.w & 0x8000;
regs.p.z = regs.x.w == 0;
}
inline void CPUcore::op_ldy_b() {
regs.y.l = rd.l;
regs.p.n = regs.y.l & 0x80;
regs.p.z = regs.y.l == 0;
}
inline void CPUcore::op_ldy_w() {
regs.y.w = rd.w;
regs.p.n = regs.y.w & 0x8000;
regs.p.z = regs.y.w == 0;
}
inline void CPUcore::op_ora_b() {
regs.a.l |= rd.l;
regs.p.n = regs.a.l & 0x80;
regs.p.z = regs.a.l == 0;
}
inline void CPUcore::op_ora_w() {
regs.a.w |= rd.w;
regs.p.n = regs.a.w & 0x8000;
regs.p.z = regs.a.w == 0;
}
inline void CPUcore::op_sbc_b() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.l ) & 15;
uint8 n1 = (regs.a.l >> 4) & 15;
n0 -= ((rd.l ) & 15) + !regs.p.c;
n1 -= ((rd.l >> 4) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n1 << 4) | (n0);
} else {
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = r >= 0;
}
regs.p.n = r & 0x80;
regs.p.v = (regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
regs.p.z = (uint8)r == 0;
regs.a.l = r;
}
inline void CPUcore::op_sbc_w() {
int r;
if(regs.p.d) {
uint8 n0 = (regs.a.w ) & 15;
uint8 n1 = (regs.a.w >> 4) & 15;
uint8 n2 = (regs.a.w >> 8) & 15;
uint8 n3 = (regs.a.w >> 12) & 15;
n0 -= ((rd.w ) & 15) + !regs.p.c;
n1 -= ((rd.w >> 4) & 15);
n2 -= ((rd.w >> 8) & 15);
n3 -= ((rd.w >> 12) & 15);
if(n0 > 9) {
n0 += 10;
n1--;
}
if(n1 > 9) {
n1 += 10;
n2--;
}
if(n2 > 9) {
n2 += 10;
n3--;
}
if(n3 > 9) {
n3 += 10;
regs.p.c = 0;
} else {
regs.p.c = 1;
}
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
} else {
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = r >= 0;
}
regs.p.n = r & 0x8000;
regs.p.v = (regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
regs.p.z = (uint16)r == 0;
regs.a.w = r;
}
inline void CPUcore::op_inc_b() {
rd.l++;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_inc_w() {
rd.w++;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_dec_b() {
rd.l--;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_dec_w() {
rd.w--;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_asl_b() {
regs.p.c = rd.l & 0x80;
rd.l <<= 1;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_asl_w() {
regs.p.c = rd.w & 0x8000;
rd.w <<= 1;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_lsr_b() {
regs.p.c = rd.l & 1;
rd.l >>= 1;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_lsr_w() {
regs.p.c = rd.w & 1;
rd.w >>= 1;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_rol_b() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.l & 0x80;
rd.l = (rd.l << 1) | carry;
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_rol_w() {
unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd.w & 0x8000;
rd.w = (rd.w << 1) | carry;
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_ror_b() {
unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = rd.l & 1;
rd.l = carry | (rd.l >> 1);
regs.p.n = rd.l & 0x80;
regs.p.z = rd.l == 0;
}
inline void CPUcore::op_ror_w() {
unsigned carry = (unsigned)regs.p.c << 15;
regs.p.c = rd.w & 1;
rd.w = carry | (rd.w >> 1);
regs.p.n = rd.w & 0x8000;
regs.p.z = rd.w == 0;
}
inline void CPUcore::op_trb_b() {
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l &= ~regs.a.l;
}
inline void CPUcore::op_trb_w() {
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w &= ~regs.a.w;
}
inline void CPUcore::op_tsb_b() {
regs.p.z = (rd.l & regs.a.l) == 0;
rd.l |= regs.a.l;
}
inline void CPUcore::op_tsb_w() {
regs.p.z = (rd.w & regs.a.w) == 0;
rd.w |= regs.a.w;
}
#endif

View File

@@ -1,37 +1,37 @@
void CPUcore::initialize_opcode_table() {
for(unsigned i = 0; i < 256 * 5; i++) op_table[i] = 0;
#ifdef CPUCORE_CPP
void CPUcore::initialize_opcode_table() {
//same implementation for all processor states
#define opA(id, name) \
op_table[table_EM + id] = &sCPU::op_ ## name; \
op_table[table_MX + id] = &sCPU::op_ ## name; \
op_table[table_Mx + id] = &sCPU::op_ ## name; \
op_table[table_mX + id] = &sCPU::op_ ## name; \
op_table[table_mx + id] = &sCPU::op_ ## name;
op_table[table_EM + id] = &CPUcore::op_ ## name; \
op_table[table_MX + id] = &CPUcore::op_ ## name; \
op_table[table_Mx + id] = &CPUcore::op_ ## name; \
op_table[table_mX + id] = &CPUcore::op_ ## name; \
op_table[table_mx + id] = &CPUcore::op_ ## name;
//implementation changes based on E processor state
#define opE(id, name) \
op_table[table_EM + id] = &sCPU::op_ ## name ## _e; \
op_table[table_MX + id] = &sCPU::op_ ## name ## _n; \
op_table[table_Mx + id] = &sCPU::op_ ## name ## _n; \
op_table[table_mX + id] = &sCPU::op_ ## name ## _n; \
op_table[table_mx + id] = &sCPU::op_ ## name ## _n; \
op_table[table_EM + id] = &CPUcore::op_ ## name ## _e; \
op_table[table_MX + id] = &CPUcore::op_ ## name ## _n; \
op_table[table_Mx + id] = &CPUcore::op_ ## name ## _n; \
op_table[table_mX + id] = &CPUcore::op_ ## name ## _n; \
op_table[table_mx + id] = &CPUcore::op_ ## name ## _n; \
//implementation changes based on M processor state
#define opM(id, name) \
op_table[table_EM + id] = &sCPU::op_ ## name ## _b; \
op_table[table_MX + id] = &sCPU::op_ ## name ## _b; \
op_table[table_Mx + id] = &sCPU::op_ ## name ## _b; \
op_table[table_mX + id] = &sCPU::op_ ## name ## _w; \
op_table[table_mx + id] = &sCPU::op_ ## name ## _w;
op_table[table_EM + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_MX + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_Mx + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_mX + id] = &CPUcore::op_ ## name ## _w; \
op_table[table_mx + id] = &CPUcore::op_ ## name ## _w;
//implementation changes based on X processor state
#define opX(id, name) \
op_table[table_EM + id] = &sCPU::op_ ## name ## _b; \
op_table[table_MX + id] = &sCPU::op_ ## name ## _b; \
op_table[table_Mx + id] = &sCPU::op_ ## name ## _w; \
op_table[table_mX + id] = &sCPU::op_ ## name ## _b; \
op_table[table_mx + id] = &sCPU::op_ ## name ## _w;
op_table[table_EM + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_MX + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_Mx + id] = &CPUcore::op_ ## name ## _w; \
op_table[table_mX + id] = &CPUcore::op_ ## name ## _b; \
op_table[table_mx + id] = &CPUcore::op_ ## name ## _w;
opE(0x00, brk) opM(0x01, ora_idpx) opE(0x02, cop) opM(0x03, ora_sr)
opM(0x04, tsb_dp) opM(0x05, ora_dp) opM(0x06, asl_dp) opM(0x07, ora_ildp)
@@ -136,3 +136,5 @@ void CPUcore::update_table() {
}
}
}
#endif

View File

@@ -1,80 +1,79 @@
struct flag_t {
bool n, v, m, x, d, i, z, c;
inline operator unsigned() const {
return (n << 7) + (v << 6) + (m << 5) + (x << 4)
+ (d << 3) + (i << 2) + (z << 1) + (c << 0);
}
inline unsigned operator=(uint8_t data) {
n = data & 0x80; v = data & 0x40; m = data & 0x20; x = data & 0x10;
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return data;
}
inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
flag_t() : n(0), v(0), m(0), x(0), d(0), i(0), z(0), c(0) {}
};
struct reg16_t {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
inline operator unsigned() const { return w; }
inline unsigned operator = (unsigned i) { return w = i; }
inline unsigned operator |= (unsigned i) { return w |= i; }
inline unsigned operator ^= (unsigned i) { return w ^= i; }
inline unsigned operator &= (unsigned i) { return w &= i; }
inline unsigned operator <<= (unsigned i) { return w <<= i; }
inline unsigned operator >>= (unsigned i) { return w >>= i; }
inline unsigned operator += (unsigned i) { return w += i; }
inline unsigned operator -= (unsigned i) { return w -= i; }
inline unsigned operator *= (unsigned i) { return w *= i; }
inline unsigned operator /= (unsigned i) { return w /= i; }
inline unsigned operator %= (unsigned i) { return w %= i; }
reg16_t() : w(0) {}
};
struct reg24_t {
union {
uint32 d;
struct { uint16 order_lsb2(w, wh); };
struct { uint8 order_lsb4(l, h, b, bh); };
};
inline operator unsigned() const { return d; }
inline unsigned operator = (unsigned i) { return d = uclip<24>(i); }
inline unsigned operator |= (unsigned i) { return d = uclip<24>(d | i); }
inline unsigned operator ^= (unsigned i) { return d = uclip<24>(d ^ i); }
inline unsigned operator &= (unsigned i) { return d = uclip<24>(d & i); }
inline unsigned operator <<= (unsigned i) { return d = uclip<24>(d << i); }
inline unsigned operator >>= (unsigned i) { return d = uclip<24>(d >> i); }
inline unsigned operator += (unsigned i) { return d = uclip<24>(d + i); }
inline unsigned operator -= (unsigned i) { return d = uclip<24>(d - i); }
inline unsigned operator *= (unsigned i) { return d = uclip<24>(d * i); }
inline unsigned operator /= (unsigned i) { return d = uclip<24>(d / i); }
inline unsigned operator %= (unsigned i) { return d = uclip<24>(d % i); }
reg24_t() : d(0) {}
};
struct regs_t {
reg24_t pc;
reg16_t a, x, y, s, d;
flag_t p;
uint8_t db;
bool e;
bool irq; //IRQ pin (0 = low, 1 = trigger)
bool wai; //raised during wai, cleared after interrupt triggered
uint32_t bus; //address on bus; -1U = I/O cycle
uint8_t mdr; //memory data register
regs_t() : db(0), e(false), irq(false), wai(false), bus(-1U), mdr(0) {}
};
struct flag_t {
bool n, v, m, x, d, i, z, c;
inline operator unsigned() const {
return (n << 7) + (v << 6) + (m << 5) + (x << 4)
+ (d << 3) + (i << 2) + (z << 1) + (c << 0);
}
inline unsigned operator=(uint8_t data) {
n = data & 0x80; v = data & 0x40; m = data & 0x20; x = data & 0x10;
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return data;
}
inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
flag_t() : n(0), v(0), m(0), x(0), d(0), i(0), z(0), c(0) {}
};
struct reg16_t {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
inline operator unsigned() const { return w; }
inline unsigned operator = (unsigned i) { return w = i; }
inline unsigned operator |= (unsigned i) { return w |= i; }
inline unsigned operator ^= (unsigned i) { return w ^= i; }
inline unsigned operator &= (unsigned i) { return w &= i; }
inline unsigned operator <<= (unsigned i) { return w <<= i; }
inline unsigned operator >>= (unsigned i) { return w >>= i; }
inline unsigned operator += (unsigned i) { return w += i; }
inline unsigned operator -= (unsigned i) { return w -= i; }
inline unsigned operator *= (unsigned i) { return w *= i; }
inline unsigned operator /= (unsigned i) { return w /= i; }
inline unsigned operator %= (unsigned i) { return w %= i; }
reg16_t() : w(0) {}
};
struct reg24_t {
union {
uint32 d;
struct { uint16 order_lsb2(w, wh); };
struct { uint8 order_lsb4(l, h, b, bh); };
};
inline operator unsigned() const { return d; }
inline unsigned operator = (unsigned i) { return d = uclip<24>(i); }
inline unsigned operator |= (unsigned i) { return d = uclip<24>(d | i); }
inline unsigned operator ^= (unsigned i) { return d = uclip<24>(d ^ i); }
inline unsigned operator &= (unsigned i) { return d = uclip<24>(d & i); }
inline unsigned operator <<= (unsigned i) { return d = uclip<24>(d << i); }
inline unsigned operator >>= (unsigned i) { return d = uclip<24>(d >> i); }
inline unsigned operator += (unsigned i) { return d = uclip<24>(d + i); }
inline unsigned operator -= (unsigned i) { return d = uclip<24>(d - i); }
inline unsigned operator *= (unsigned i) { return d = uclip<24>(d * i); }
inline unsigned operator /= (unsigned i) { return d = uclip<24>(d / i); }
inline unsigned operator %= (unsigned i) { return d = uclip<24>(d % i); }
reg24_t() : d(0) {}
};
struct regs_t {
reg24_t pc;
reg16_t a, x, y, s, d;
flag_t p;
uint8_t db;
bool e;
bool irq; //IRQ pin (0 = low, 1 = trigger)
bool wai; //raised during wai, cleared after interrupt triggered
uint8_t mdr; //memory data register
regs_t() : db(0), e(false), irq(false), wai(false), mdr(0) {}
};

View File

@@ -1,15 +1,19 @@
#include <../base.hpp>
#define CPU_CPP
void CPU::power() {
cpu_version = snes.config.cpu.version;
}
void CPU::reset() {
}
CPU::CPU() {
}
CPU::~CPU() {
}
namespace SNES {
void CPU::power() {
cpu_version = config.cpu.version;
}
void CPU::reset() {
}
CPU::CPU() {
}
CPU::~CPU() {
}
};

View File

@@ -1,22 +1,22 @@
class CPU : public MMIO {
public:
virtual void enter() = 0;
//CPU version number
//* 1 and 2 are known
//* reported by $4210
//* affects timing (DRAM refresh, HDMA init, etc)
uint8 cpu_version;
virtual uint8 pio() = 0;
virtual bool joylatch() = 0;
virtual uint8 port_read(uint8 port) = 0;
class CPU : public MMIO {
public:
virtual void enter() = 0;
//CPU version number
//* 1 and 2 are known
//* reported by $4210
//* affects timing (DRAM refresh, HDMA init, etc)
uint8 cpu_version;
virtual uint8 pio() = 0;
virtual bool joylatch() = 0;
virtual uint8 port_read(uint8 port) = 0;
virtual void port_write(uint8 port, uint8 value) = 0;
virtual void scanline() = 0;
virtual void power();
virtual void reset();
CPU();
virtual ~CPU();
};
virtual void scanline() = 0;
virtual void power();
virtual void reset();
CPU();
virtual ~CPU();
};

View File

@@ -270,4 +270,4 @@ void sCPU::dma_reset() {
}
}
#endif //ifdef SCPU_CPP
#endif

View File

@@ -1,71 +1,71 @@
struct {
//$420b
bool dma_enabled;
//$420c
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
bool hdma_indirect;
bool reversexfer;
bool fixedxfer;
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_ibank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 unknown;
//internal variables
bool hdma_completed;
bool hdma_do_transfer;
} channel[8];
void dma_add_clocks(unsigned clocks);
bool dma_addr_valid(uint32 abus);
uint8 dma_read(uint32 abus);
void dma_transfer(bool direction, uint8 bbus, uint32 abus);
uint8 dma_bbus(uint8 i, uint8 index);
uint32 dma_addr(uint8 i);
uint32 hdma_addr(uint8 i);
uint32 hdma_iaddr(uint8 i);
uint8 dma_enabled_channels();
void dma_run();
bool hdma_active(uint8 i);
bool hdma_active_after(uint8 i);
uint8 hdma_enabled_channels();
uint8 hdma_active_channels();
void hdma_update(uint8 i);
void hdma_run();
void hdma_init_reset();
void hdma_init();
void dma_power();
void dma_reset();
struct {
//$420b
bool dma_enabled;
//$420c
bool hdma_enabled;
//$43x0
uint8 dmap;
bool direction;
bool hdma_indirect;
bool reversexfer;
bool fixedxfer;
uint8 xfermode;
//$43x1
uint8 destaddr;
//$43x2-$43x3
uint16 srcaddr;
//$43x4
uint8 srcbank;
//$43x5-$43x6
union {
uint16 xfersize;
uint16 hdma_iaddr;
};
//$43x7
uint8 hdma_ibank;
//$43x8-$43x9
uint16 hdma_addr;
//$43xa
uint8 hdma_line_counter;
//$43xb/$43xf
uint8 unknown;
//internal variables
bool hdma_completed;
bool hdma_do_transfer;
} channel[8];
void dma_add_clocks(unsigned clocks);
bool dma_addr_valid(uint32 abus);
uint8 dma_read(uint32 abus);
void dma_transfer(bool direction, uint8 bbus, uint32 abus);
uint8 dma_bbus(uint8 i, uint8 index);
uint32 dma_addr(uint8 i);
uint32 hdma_addr(uint8 i);
uint32 hdma_iaddr(uint8 i);
uint8 dma_enabled_channels();
void dma_run();
bool hdma_active(uint8 i);
bool hdma_active_after(uint8 i);
uint8 hdma_enabled_channels();
uint8 hdma_active_channels();
void hdma_update(uint8 i);
void hdma_run();
void hdma_init_reset();
void hdma_init();
void dma_power();
void dma_reset();

View File

@@ -1,36 +1,27 @@
#ifdef SCPU_CPP
void sCPU::op_io() {
regs.bus = -1U;
status.clock_count = 6;
precycle_edge();
add_clocks(6);
if(regs.wai) scheduler.sync_cpucop();
cycle_edge();
add_clocks(6);
}
uint8 sCPU::op_read(uint32 addr) {
status.clock_count = speed(regs.bus = addr);
precycle_edge();
status.clock_count = speed(addr);
cycle_edge();
add_clocks(status.clock_count - 4);
scheduler.sync_cpucop();
scheduler.sync_cpuppu();
regs.mdr = bus.read(addr);
add_clocks(4);
cycle_edge();
return regs.mdr;
}
void sCPU::op_write(uint32 addr, uint8 data) {
status.clock_count = speed(regs.bus = addr);
precycle_edge();
add_clocks(status.clock_count);
scheduler.sync_cpucop();
scheduler.sync_cpuppu();
bus.write(addr, regs.mdr = data);
status.clock_count = speed(addr);
cycle_edge();
add_clocks(status.clock_count);
scheduler.sync_cpucop();
bus.write(addr, regs.mdr = data);
}
unsigned sCPU::speed(unsigned addr) const {

View File

@@ -1,16 +1,16 @@
//============================
//CPU<>APU communication ports
//============================
uint8 apu_port[4];
uint8 port_read(uint8 port) { return apu_port[port & 3]; }
void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; }
//======================
//core CPU bus functions
//======================
void op_io();
uint8 op_read(uint32 addr);
void op_write(uint32 addr, uint8 data);
alwaysinline unsigned speed(unsigned addr) const;
//============================
//CPU<>APU communication ports
//============================
uint8 apu_port[4];
uint8 port_read(uint8 port) { return apu_port[port & 3]; }
void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; }
//======================
//core CPU bus functions
//======================
void op_io();
uint8 op_read(uint32 addr);
void op_write(uint32 addr, uint8 data);
alwaysinline unsigned speed(unsigned addr) const;

View File

@@ -42,7 +42,7 @@ void sCPU::mmio_w4016(uint8 data) {
status.joypad_strobe_latch = !!(data & 1);
if(status.joypad_strobe_latch == 1) {
snes.input.poll();
input.poll();
}
}
@@ -54,7 +54,7 @@ void sCPU::mmio_w4016(uint8 data) {
//realtime or buffered status of joypadN.b
uint8 sCPU::mmio_r4016() {
uint8 r = regs.mdr & 0xfc;
r |= snes.input.port_read(0) & 3;
r |= input.port_read(0) & 3;
return r;
}
@@ -64,7 +64,7 @@ uint8 sCPU::mmio_r4016() {
//1-0 = Joypad serial data
uint8 sCPU::mmio_r4017() {
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= snes.input.port_read(1) & 3;
r |= input.port_read(1) & 3;
return r;
}
@@ -93,7 +93,7 @@ void sCPU::mmio_w4203(uint8 data) {
status.r4216 = status.mul_a * status.mul_b;
status.alu_lock = true;
event.enqueue(snes.config.cpu.alu_mul_delay, EventAluLockRelease);
event.enqueue(config.cpu.alu_mul_delay, EventAluLockRelease);
}
//WRDIVL
@@ -113,7 +113,7 @@ void sCPU::mmio_w4206(uint8 data) {
status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a;
status.alu_lock = true;
event.enqueue(snes.config.cpu.alu_div_delay, EventAluLockRelease);
event.enqueue(config.cpu.alu_div_delay, EventAluLockRelease);
}
//HTIMEL
@@ -534,4 +534,4 @@ void sCPU::mmio_write(unsigned addr, uint8 data) {
}
}
#endif //ifdef SCPU_CPP
#endif

View File

@@ -1,71 +1,71 @@
void mmio_power();
void mmio_reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 pio();
bool joylatch();
uint8 mmio_r2180();
uint8 mmio_r4016();
uint8 mmio_r4017();
uint8 mmio_r4210();
uint8 mmio_r4211();
uint8 mmio_r4212();
uint8 mmio_r4213();
uint8 mmio_r4214();
uint8 mmio_r4215();
uint8 mmio_r4216();
uint8 mmio_r4217();
uint8 mmio_r4218();
uint8 mmio_r4219();
uint8 mmio_r421a();
uint8 mmio_r421b();
uint8 mmio_r421c();
uint8 mmio_r421d();
uint8 mmio_r421e();
uint8 mmio_r421f();
uint8 mmio_r43x0(uint8 i);
uint8 mmio_r43x1(uint8 i);
uint8 mmio_r43x2(uint8 i);
uint8 mmio_r43x3(uint8 i);
uint8 mmio_r43x4(uint8 i);
uint8 mmio_r43x5(uint8 i);
uint8 mmio_r43x6(uint8 i);
uint8 mmio_r43x7(uint8 i);
uint8 mmio_r43x8(uint8 i);
uint8 mmio_r43x9(uint8 i);
uint8 mmio_r43xa(uint8 i);
uint8 mmio_r43xb(uint8 i);
void mmio_w2180(uint8 data);
void mmio_w2181(uint8 data);
void mmio_w2182(uint8 data);
void mmio_w2183(uint8 data);
void mmio_w4016(uint8 data);
void mmio_w4200(uint8 data);
void mmio_w4201(uint8 data);
void mmio_w4202(uint8 data);
void mmio_w4203(uint8 data);
void mmio_w4204(uint8 data);
void mmio_w4205(uint8 data);
void mmio_w4206(uint8 data);
void mmio_w4207(uint8 data);
void mmio_w4208(uint8 data);
void mmio_w4209(uint8 data);
void mmio_w420a(uint8 data);
void mmio_w420b(uint8 data);
void mmio_w420c(uint8 data);
void mmio_w420d(uint8 data);
void mmio_w43x0(uint8 i, uint8 data);
void mmio_w43x1(uint8 i, uint8 data);
void mmio_w43x2(uint8 i, uint8 data);
void mmio_w43x3(uint8 i, uint8 data);
void mmio_w43x4(uint8 i, uint8 data);
void mmio_w43x5(uint8 i, uint8 data);
void mmio_w43x6(uint8 i, uint8 data);
void mmio_w43x7(uint8 i, uint8 data);
void mmio_w43x8(uint8 i, uint8 data);
void mmio_w43x9(uint8 i, uint8 data);
void mmio_w43xa(uint8 i, uint8 data);
void mmio_w43xb(uint8 i, uint8 data);
void mmio_power();
void mmio_reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 pio();
bool joylatch();
uint8 mmio_r2180();
uint8 mmio_r4016();
uint8 mmio_r4017();
uint8 mmio_r4210();
uint8 mmio_r4211();
uint8 mmio_r4212();
uint8 mmio_r4213();
uint8 mmio_r4214();
uint8 mmio_r4215();
uint8 mmio_r4216();
uint8 mmio_r4217();
uint8 mmio_r4218();
uint8 mmio_r4219();
uint8 mmio_r421a();
uint8 mmio_r421b();
uint8 mmio_r421c();
uint8 mmio_r421d();
uint8 mmio_r421e();
uint8 mmio_r421f();
uint8 mmio_r43x0(uint8 i);
uint8 mmio_r43x1(uint8 i);
uint8 mmio_r43x2(uint8 i);
uint8 mmio_r43x3(uint8 i);
uint8 mmio_r43x4(uint8 i);
uint8 mmio_r43x5(uint8 i);
uint8 mmio_r43x6(uint8 i);
uint8 mmio_r43x7(uint8 i);
uint8 mmio_r43x8(uint8 i);
uint8 mmio_r43x9(uint8 i);
uint8 mmio_r43xa(uint8 i);
uint8 mmio_r43xb(uint8 i);
void mmio_w2180(uint8 data);
void mmio_w2181(uint8 data);
void mmio_w2182(uint8 data);
void mmio_w2183(uint8 data);
void mmio_w4016(uint8 data);
void mmio_w4200(uint8 data);
void mmio_w4201(uint8 data);
void mmio_w4202(uint8 data);
void mmio_w4203(uint8 data);
void mmio_w4204(uint8 data);
void mmio_w4205(uint8 data);
void mmio_w4206(uint8 data);
void mmio_w4207(uint8 data);
void mmio_w4208(uint8 data);
void mmio_w4209(uint8 data);
void mmio_w420a(uint8 data);
void mmio_w420b(uint8 data);
void mmio_w420c(uint8 data);
void mmio_w420d(uint8 data);
void mmio_w43x0(uint8 i, uint8 data);
void mmio_w43x1(uint8 i, uint8 data);
void mmio_w43x2(uint8 i, uint8 data);
void mmio_w43x3(uint8 i, uint8 data);
void mmio_w43x4(uint8 i, uint8 data);
void mmio_w43x5(uint8 i, uint8 data);
void mmio_w43x6(uint8 i, uint8 data);
void mmio_w43x7(uint8 i, uint8 data);
void mmio_w43x8(uint8 i, uint8 data);
void mmio_w43x9(uint8 i, uint8 data);
void mmio_w43xa(uint8 i, uint8 data);
void mmio_w43xb(uint8 i, uint8 data);

View File

@@ -1,100 +1,100 @@
#include <../base.hpp>
#define SCPU_CPP
#include <nall/priorityqueue.hpp>
priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
#include "dma/dma.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
void sCPU::enter() {
regs.pc.l = bus.read(0xfffc);
regs.pc.h = bus.read(0xfffd);
//initial latch values for $213c/$213d
//[x]0035 : [y]0000 (53.0 -> 212) [lda $2137]
//[x]0038 : [y]0000 (56.5 -> 226) [nop : lda $2137]
add_clocks(186);
while(true) {
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
} else if(status.irq_pending) {
status.irq_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
}
op_irq();
}
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
(this->*opcode_table[op_readpc()])();
}
}
void sCPU::op_irq() {
op_read(regs.pc.d);
op_io();
if(!regs.e) op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
op_writestack(regs.pc.l);
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
rd.l = op_read(status.interrupt_vector + 0);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
rd.h = op_read(status.interrupt_vector + 1);
regs.pc.w = rd.w;
}
void sCPU::power() {
CPU::power();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
mmio_power();
dma_power();
timing_power();
reset();
}
void sCPU::reset() {
CPU::reset();
//note: some registers are not fully reset by SNES
regs.pc = 0x000000;
regs.x.h = 0x00;
regs.y.h = 0x00;
regs.s.h = 0x01;
regs.d = 0x0000;
regs.db = 0x00;
regs.p = 0x34;
regs.e = 1;
regs.mdr = 0x00;
regs.wai = false;
update_table();
status.interrupt_pending = false;
status.interrupt_vector = 0xfffc; //reset vector address
mmio_reset();
dma_reset();
timing_reset();
apu_port[0] = 0x00;
apu_port[1] = 0x00;
apu_port[2] = 0x00;
apu_port[3] = 0x00;
}
sCPU::sCPU() {
}
sCPU::~sCPU() {
}
#include <../base.hpp>
#include <nall/priorityqueue.hpp>
#define SCPU_CPP
namespace SNES {
priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
#include "dma/dma.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
void sCPU::enter() {
regs.pc.l = bus.read(0xfffc);
regs.pc.h = bus.read(0xfffd);
add_clocks(186);
while(true) {
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
} else if(status.irq_pending) {
status.irq_pending = false;
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
}
op_irq();
}
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
(this->*opcode_table[op_readpc()])();
}
}
void sCPU::op_irq() {
op_read(regs.pc.d);
op_io();
if(!regs.e) op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
op_writestack(regs.pc.l);
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
rd.l = op_read(status.interrupt_vector + 0);
regs.pc.b = 0x00;
regs.p.i = 1;
regs.p.d = 0;
rd.h = op_read(status.interrupt_vector + 1);
regs.pc.w = rd.w;
}
void sCPU::power() {
CPU::power();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
mmio_power();
dma_power();
timing_power();
reset();
}
void sCPU::reset() {
CPU::reset();
//note: some registers are not fully reset by SNES
regs.pc = 0x000000;
regs.x.h = 0x00;
regs.y.h = 0x00;
regs.s.h = 0x01;
regs.d = 0x0000;
regs.db = 0x00;
regs.p = 0x34;
regs.e = 1;
regs.mdr = 0x00;
regs.wai = false;
update_table();
status.interrupt_pending = false;
status.interrupt_vector = 0xfffc; //reset vector address
mmio_reset();
dma_reset();
timing_reset();
apu_port[0] = 0x00;
apu_port[1] = 0x00;
apu_port[2] = 0x00;
apu_port[3] = 0x00;
}
sCPU::sCPU() {
}
sCPU::~sCPU() {
}
};

View File

@@ -1,93 +1,91 @@
class sCPU : public CPU, public CPUcore {
public:
void enter();
void op_irq();
bool interrupt_pending() { return status.interrupt_pending; }
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
enum DmaState { DmaInactive, DmaRun, DmaCpuSync };
struct {
bool interrupt_pending;
uint16 interrupt_vector;
unsigned clock_count;
unsigned line_clocks;
//timing
bool irq_lock;
bool alu_lock;
unsigned dram_refresh_position;
bool nmi_valid;
bool nmi_line;
bool nmi_transition;
bool nmi_pending;
bool nmi_hold;
bool irq_valid;
bool irq_line;
bool irq_transition;
bool irq_pending;
bool irq_hold;
//DMA
unsigned dma_counter;
unsigned dma_clocks;
bool dma_pending;
bool hdma_pending;
bool hdma_mode; //0 = init, 1 = run
DmaState dma_state;
public:
void enter();
void op_irq();
bool interrupt_pending() { return status.interrupt_pending; }
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
struct {
bool interrupt_pending;
uint16 interrupt_vector;
unsigned clock_count;
unsigned line_clocks;
//timing
bool irq_lock;
bool alu_lock;
unsigned dram_refresh_position;
bool nmi_valid;
bool nmi_line;
bool nmi_transition;
bool nmi_pending;
bool nmi_hold;
bool irq_valid;
bool irq_line;
bool irq_transition;
bool irq_pending;
bool irq_hold;
//DMA
bool dma_active;
unsigned dma_counter;
unsigned dma_clocks;
bool dma_pending;
bool hdma_pending;
bool hdma_mode; //0 = init, 1 = run
//MMIO
//$2181-$2183
uint32 wram_addr;
//$4016-$4017
bool joypad_strobe_latch;
uint32 joypad1_bits;
uint32 joypad2_bits;
//$4200
bool nmi_enabled;
bool hirq_enabled, virq_enabled;
bool auto_joypad_poll;
//$4201
uint8 pio;
//$4202-$4203
uint8 mul_a, mul_b;
//$4204-$4206
uint16 div_a;
uint8 div_b;
//$4207-$420a
uint16 hirq_pos, virq_pos;
//$420d
unsigned rom_speed;
//$4214-$4217
uint16 r4214;
uint16 r4216;
//$4218-$421f
uint8 joy1l, joy1h;
uint8 joy2l, joy2h;
uint8 joy3l, joy3h;
uint8 joy4l, joy4h;
} status;
void power();
void reset();
sCPU();
~sCPU();
};
//$2181-$2183
uint32 wram_addr;
//$4016-$4017
bool joypad_strobe_latch;
uint32 joypad1_bits;
uint32 joypad2_bits;
//$4200
bool nmi_enabled;
bool hirq_enabled, virq_enabled;
bool auto_joypad_poll;
//$4201
uint8 pio;
//$4202-$4203
uint8 mul_a, mul_b;
//$4204-$4206
uint16 div_a;
uint8 div_b;
//$4207-$420a
uint16 hirq_pos, virq_pos;
//$420d
unsigned rom_speed;
//$4214-$4217
uint16 r4214;
uint16 r4216;
//$4218-$421f
uint8 joy1l, joy1h;
uint8 joy2l, joy2h;
uint8 joy3l, joy3h;
uint8 joy4l, joy4h;
} status;
void power();
void reset();
sCPU();
~sCPU();
};

View File

@@ -1,93 +1,93 @@
#ifdef SCPU_CPP
//called once every four clock cycles;
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
//
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
//it is used to emulate hardware communication delay between opcode and interrupt units.
void sCPU::poll_interrupts() {
//NMI hold
if(status.nmi_hold) {
status.nmi_hold = false;
if(status.nmi_enabled) status.nmi_transition = true;
}
//NMI test
bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240));
if(!status.nmi_valid && nmi_valid) {
//0->1 edge sensitive transition
status.nmi_line = true;
status.nmi_hold = true; //hold /NMI for four cycles
} else if(status.nmi_valid && !nmi_valid) {
//1->0 edge sensitive transition
status.nmi_line = false;
}
status.nmi_valid = nmi_valid;
//IRQ hold
status.irq_hold = false;
if(status.irq_line) {
if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
}
//IRQ test
bool irq_valid = (status.virq_enabled || status.hirq_enabled);
if(irq_valid) {
if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos))
|| (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4)
|| (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irq_valid = false;
}
if(!status.irq_valid && irq_valid) {
//0->1 edge sensitive transition
status.irq_line = true;
status.irq_hold = true; //hold /IRQ for four cycles
}
status.irq_valid = irq_valid;
}
void sCPU::nmitimen_update(uint8 data) {
bool nmi_enabled = status.nmi_enabled;
bool virq_enabled = status.virq_enabled;
bool hirq_enabled = status.hirq_enabled;
status.nmi_enabled = data & 0x80;
status.virq_enabled = data & 0x20;
status.hirq_enabled = data & 0x10;
//0->1 edge sensitive transition
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
status.nmi_transition = true;
}
//?->1 level sensitive transition
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
status.irq_transition = true;
}
if(!status.virq_enabled && !status.hirq_enabled) {
status.irq_line = false;
status.irq_transition = false;
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
bool sCPU::rdnmi() {
bool result = status.nmi_line;
if(!status.nmi_hold) {
status.nmi_line = false;
}
return result;
}
bool sCPU::timeup() {
bool result = status.irq_line;
if(!status.irq_hold) {
status.irq_line = false;
status.irq_transition = false;
}
return result;
#ifdef SCPU_CPP
//called once every four clock cycles;
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
//
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
//it is used to emulate hardware communication delay between opcode and interrupt units.
void sCPU::poll_interrupts() {
//NMI hold
if(status.nmi_hold) {
status.nmi_hold = false;
if(status.nmi_enabled) status.nmi_transition = true;
}
//NMI test
bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240));
if(!status.nmi_valid && nmi_valid) {
//0->1 edge sensitive transition
status.nmi_line = true;
status.nmi_hold = true; //hold /NMI for four cycles
} else if(status.nmi_valid && !nmi_valid) {
//1->0 edge sensitive transition
status.nmi_line = false;
}
status.nmi_valid = nmi_valid;
//IRQ hold
status.irq_hold = false;
if(status.irq_line) {
if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
}
//IRQ test
bool irq_valid = (status.virq_enabled || status.hirq_enabled);
if(irq_valid) {
if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos))
|| (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4)
|| (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irq_valid = false;
}
if(!status.irq_valid && irq_valid) {
//0->1 edge sensitive transition
status.irq_line = true;
status.irq_hold = true; //hold /IRQ for four cycles
}
status.irq_valid = irq_valid;
}
void sCPU::nmitimen_update(uint8 data) {
bool nmi_enabled = status.nmi_enabled;
bool virq_enabled = status.virq_enabled;
bool hirq_enabled = status.hirq_enabled;
status.nmi_enabled = data & 0x80;
status.virq_enabled = data & 0x20;
status.hirq_enabled = data & 0x10;
//0->1 edge sensitive transition
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
status.nmi_transition = true;
}
//?->1 level sensitive transition
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
status.irq_transition = true;
}
if(!status.virq_enabled && !status.hirq_enabled) {
status.irq_line = false;
status.irq_transition = false;
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
bool sCPU::rdnmi() {
bool result = status.nmi_line;
if(!status.nmi_hold) {
status.nmi_line = false;
}
return result;
}
bool sCPU::timeup() {
bool result = status.irq_line;
if(!status.irq_hold) {
status.irq_line = false;
status.irq_transition = false;
}
return result;
}
bool sCPU::nmi_test() {
@@ -97,11 +97,11 @@ bool sCPU::nmi_test() {
return true;
}
bool sCPU::irq_test() {
bool sCPU::irq_test() {
if(!status.irq_transition && !regs.irq) return false;
status.irq_transition = false;
status.irq_transition = false;
regs.wai = false;
return !regs.p.i;
}
}
#endif
#endif

View File

@@ -1,28 +1,28 @@
#ifdef SCPU_CPP
void sCPU::run_auto_joypad_poll() {
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
for(unsigned i = 0; i < 16; i++) {
uint8 port0 = snes.input.port_read(0);
uint8 port1 = snes.input.port_read(1);
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
joy3 |= (port0 & 2) ? (0x8000 >> i) : 0;
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
}
status.joy1l = joy1;
status.joy1h = joy1 >> 8;
status.joy2l = joy2;
status.joy2h = joy2 >> 8;
status.joy3l = joy3;
status.joy3h = joy3 >> 8;
status.joy4l = joy4;
status.joy4h = joy4 >> 8;
}
void sCPU::run_auto_joypad_poll() {
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
for(unsigned i = 0; i < 16; i++) {
uint8 port0 = input.port_read(0);
uint8 port1 = input.port_read(1);
#endif
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
joy3 |= (port0 & 2) ? (0x8000 >> i) : 0;
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
}
status.joy1l = joy1;
status.joy1h = joy1 >> 8;
status.joy2l = joy2;
status.joy2h = joy2 >> 8;
status.joy3l = joy3;
status.joy3h = joy3 >> 8;
status.joy4l = joy4;
status.joy4h = joy4 >> 8;
}
#endif

View File

@@ -13,25 +13,28 @@ void sCPU::add_clocks(unsigned clocks) {
unsigned ticks = clocks >> 1;
while(ticks--) {
ppu.tick();
if((ppu.hcounter() & 2) == 0) {
snes.input.tick();
} else {
if(ppu.hcounter() & 2) {
input.tick();
poll_interrupts();
}
}
scheduler.addclocks_cpu(clocks);
}
//called by ppu.tick() when Hcounter=0
void sCPU::scanline() {
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
status.line_clocks = ppu.lineclocks();
//forcefully sync S-CPU to other processors, in case chips are not communicating
scheduler.sync_cpuppu();
scheduler.sync_cpucop();
scheduler.sync_cpusmp();
system.scanline();
if(ppu.vcounter() == 0) {
//hdma init triggers once every frame
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
//forcefully sync S-CPU and S-SMP, in case chips are not communicating
scheduler.sync_cpusmp();
}
//dram refresh occurs once every scanline
@@ -44,19 +47,11 @@ void sCPU::scanline() {
}
if(status.auto_joypad_poll == true && ppu.vcounter() == (ppu.overscan() == false ? 227 : 242)) {
snes.input.poll();
input.poll();
run_auto_joypad_poll();
}
}
//used for H/DMA bus synchronization
void sCPU::precycle_edge() {
if(status.dma_state == DmaCpuSync) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_state = DmaInactive;
}
}
//used to test for H/DMA, which can trigger on the edge of every opcode cycle.
void sCPU::cycle_edge() {
while(cycle_edge_state) {
@@ -88,30 +83,34 @@ void sCPU::cycle_edge() {
//.. Run one bus CPU cycle
//.. CPU sync
if(status.dma_state == DmaRun) {
if(status.dma_active == true) {
if(status.hdma_pending) {
status.hdma_pending = false;
if(hdma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync
dma_add_clocks(8 - dma_counter());
status.hdma_mode == 0 ? hdma_init() : hdma_run();
if(!dma_enabled_channels()) status.dma_state = DmaCpuSync;
if(!dma_enabled_channels()) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
}
}
if(status.dma_pending) {
status.dma_pending = false;
if(dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync
dma_add_clocks(8 - dma_counter());
dma_run();
status.dma_state = DmaCpuSync;
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
}
}
if(status.dma_state == DmaInactive) {
if(status.dma_active == false) {
if(status.dma_pending || status.hdma_pending) {
status.dma_clocks = 0;
status.dma_state = DmaRun;
status.dma_active = true;
}
}
}
@@ -156,12 +155,12 @@ void sCPU::timing_reset() {
status.irq_pending = false;
status.irq_hold = false;
status.dma_active = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.dma_state = DmaInactive;
cycle_edge_state = 0;
}

View File

@@ -1,41 +1,40 @@
enum {
EventNone,
EventIrqLockRelease,
EventAluLockRelease,
EventDramRefresh,
EventHdmaInit,
EventHdmaRun,
//cycle edge
EventFlagHdmaInit = 1 << 0,
EventFlagHdmaRun = 1 << 1,
};
unsigned cycle_edge_state;
//timing.cpp
unsigned dma_counter();
void add_clocks(unsigned clocks);
void scanline();
alwaysinline void precycle_edge();
alwaysinline void cycle_edge();
void last_cycle();
void timing_power();
void timing_reset();
//irq.cpp
alwaysinline void poll_interrupts();
void nmitimen_update(uint8 data);
bool rdnmi();
bool timeup();
alwaysinline bool nmi_test();
alwaysinline bool irq_test();
//joypad.cpp
void run_auto_joypad_poll();
//event.cpp
void queue_event(unsigned); //priorityqueue callback function
enum {
EventNone,
EventIrqLockRelease,
EventAluLockRelease,
EventDramRefresh,
EventHdmaInit,
EventHdmaRun,
//cycle edge
EventFlagHdmaInit = 1 << 0,
EventFlagHdmaRun = 1 << 1,
};
unsigned cycle_edge_state;
//timing.cpp
unsigned dma_counter();
void add_clocks(unsigned clocks);
void scanline();
alwaysinline void cycle_edge();
alwaysinline void last_cycle();
void timing_power();
void timing_reset();
//irq.cpp
alwaysinline void poll_interrupts();
void nmitimen_update(uint8 data);
bool rdnmi();
bool timeup();
alwaysinline bool nmi_test();
alwaysinline bool irq_test();
//joypad.cpp
void run_auto_joypad_poll();
//event.cpp
void queue_event(unsigned); //priorityqueue callback function

Some files were not shown because too many files have changed in this diff Show More