mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-23 23:41:35 +02:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7b0e484c18 | ||
|
f8e425ff49 | ||
|
2a6a66f478 | ||
|
3c42e6caa0 | ||
|
5f96547beb | ||
|
44b5f1bf27 |
274
src/Makefile
274
src/Makefile
@@ -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)"
|
||||
|
12
src/base.hpp
12
src/base.hpp
@@ -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>
|
||||
|
@@ -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;
|
||||
}
|
@@ -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;
|
@@ -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
|
@@ -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
157
src/cartridge/cartridge.cpp
Normal 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
131
src/cartridge/cartridge.hpp
Normal 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;
|
@@ -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 {
|
@@ -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
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#make platform=x compiler=gcc
|
||||
make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
@@ -1,5 +1,8 @@
|
||||
#include <../base.hpp>
|
||||
|
||||
#define CHEAT_CPP
|
||||
namespace SNES {
|
||||
|
||||
Cheat cheat;
|
||||
|
||||
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
|
||||
@@ -178,9 +181,7 @@ void Cheat::disable(unsigned i) {
|
||||
//...
|
||||
//===============================
|
||||
|
||||
bool Cheat::load(const char *fn) {
|
||||
string data;
|
||||
if(!data.readfile(fn)) return false;
|
||||
void Cheat::load(string data) {
|
||||
data.replace("\r\n", "\n");
|
||||
data.qreplace(" ", "");
|
||||
|
||||
@@ -193,21 +194,16 @@ bool Cheat::load(const char *fn) {
|
||||
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;
|
||||
string Cheat::save() const {
|
||||
string data;
|
||||
for(unsigned i = 0; i < code.size(); i++) {
|
||||
fp.print(string()
|
||||
<< "\"" << code[i].desc << "\", "
|
||||
data << "\"" << code[i].desc << "\", "
|
||||
<< (code[i].enabled ? "enabled, " : "disabled, ")
|
||||
<< code[i].code << "\r\n");
|
||||
<< code[i].code << "\r\n";
|
||||
}
|
||||
fp.close();
|
||||
return true;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Cheat::clear() {
|
||||
@@ -390,3 +386,6 @@ string& Cheat::decode_description(string &desc) const {
|
||||
desc.replace("\\n", "\n");
|
||||
return desc;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@@ -38,8 +38,8 @@ public:
|
||||
void enable(unsigned i);
|
||||
void disable(unsigned i);
|
||||
|
||||
bool load(const char *fn);
|
||||
bool save(const char *fn) const;
|
||||
void load(string data);
|
||||
string save() const;
|
||||
void clear();
|
||||
|
||||
Cheat();
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#include <../cart/cart.hpp>
|
||||
#define BSX_CPP
|
||||
|
||||
#include "bsx.hpp"
|
||||
#define BSX_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "bsx_base.cpp"
|
||||
#include "bsx_cart.cpp"
|
||||
#include "bsx_flash.cpp"
|
||||
};
|
||||
|
||||
|
@@ -32,16 +32,10 @@ public:
|
||||
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;
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#include "sgb/sgb.hpp"
|
||||
#include "superfx/superfx.hpp"
|
||||
#include "sa1/sa1.hpp"
|
||||
#include "bsx/bsx.hpp"
|
||||
#include "srtc/srtc.hpp"
|
||||
|
@@ -6,9 +6,12 @@
|
||||
*/
|
||||
|
||||
#include <../base.hpp>
|
||||
#define CX4_CPP
|
||||
|
||||
#include "cx4.hpp"
|
||||
#define CX4_CPP
|
||||
namespace SNES {
|
||||
|
||||
Cx4 cx4;
|
||||
|
||||
#include "cx4data.cpp"
|
||||
#include "cx4fn.cpp"
|
||||
#include "cx4oam.cpp"
|
||||
@@ -195,3 +198,5 @@ void Cx4::reset() {
|
||||
memset(ram, 0, 0x0c00);
|
||||
memset(reg, 0, 0x0100);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#include <../cart/cart.hpp>
|
||||
#define DSP1_CPP
|
||||
|
||||
#include "dsp1.hpp"
|
||||
#define DSP1_CPP
|
||||
namespace SNES {
|
||||
|
||||
DSP1 dsp1;
|
||||
|
||||
#include "dsp1emu.cpp"
|
||||
|
||||
void DSP1::init() {}
|
||||
@@ -57,3 +59,5 @@ void DSP1::write(unsigned addr, uint8 data) {
|
||||
dsp1.setDr(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#define DSP2_CPP
|
||||
|
||||
#include "dsp2.hpp"
|
||||
#define DSP2_CPP
|
||||
namespace SNES {
|
||||
|
||||
DSP2 dsp2;
|
||||
|
||||
#include "dsp2_op.cpp"
|
||||
|
||||
void DSP2::init() {}
|
||||
@@ -134,3 +137,5 @@ void DSP2::write(unsigned addr, uint8 data) {
|
||||
|
||||
DSP2::DSP2() {}
|
||||
DSP2::~DSP2() {}
|
||||
};
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#define DSP3_CPP
|
||||
|
||||
#include "dsp3.hpp"
|
||||
#define DSP3_CPP
|
||||
namespace SNES {
|
||||
|
||||
DSP3 dsp3;
|
||||
|
||||
namespace DSP3i {
|
||||
#define bool8 uint8
|
||||
#include "dsp3emu.c"
|
||||
@@ -33,3 +36,5 @@ void DSP3::write(unsigned addr, uint8 data) {
|
||||
DSP3i::dsp3_byte = data;
|
||||
DSP3i::DSP3SetByte();
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#define DSP4_CPP
|
||||
|
||||
#include "dsp4.hpp"
|
||||
#define DSP4_CPP
|
||||
namespace SNES {
|
||||
|
||||
DSP4 dsp4;
|
||||
|
||||
namespace DSP4i {
|
||||
inline uint16 READ_WORD(uint8 *addr) {
|
||||
return (addr[0]) + (addr[1] << 8);
|
||||
@@ -53,3 +56,5 @@ void DSP4::write(unsigned addr, uint8 data) {
|
||||
DSP4i::DSP4SetByte();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -1,6 +1,9 @@
|
||||
#include <../base.hpp>
|
||||
#include <../cart/cart.hpp>
|
||||
#include "obc1.hpp"
|
||||
|
||||
#define OBC1_CPP
|
||||
namespace SNES {
|
||||
|
||||
OBC1 obc1;
|
||||
|
||||
void OBC1::init() {}
|
||||
void OBC1::enable() {}
|
||||
@@ -70,3 +73,5 @@ void OBC1::ram_write(unsigned addr, uint8 data) {
|
||||
|
||||
OBC1::OBC1() {}
|
||||
OBC1::~OBC1() {}
|
||||
|
||||
};
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
@@ -112,6 +113,7 @@ void SA1::mmio_w220b(uint8_t data) {
|
||||
mmio.sa1_nmicl = (data & 0x10);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
} 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;
|
||||
mmio.timer_irqcl = 1;
|
||||
regs.wai = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||
} else 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) {
|
||||
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||
status.interrupt_pending = true;
|
||||
status.interrupt_vector = mmio.civ;
|
||||
mmio.sa1_irqfl = true;
|
||||
regs.wai = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,18 +139,13 @@ 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;
|
||||
|
||||
//$2200 CCNT
|
||||
@@ -339,3 +313,5 @@ void SA1::reset() {
|
||||
|
||||
SA1::SA1() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -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();
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#include <../cart/cart.hpp>
|
||||
#define SDD1_CPP
|
||||
|
||||
#include "sdd1.hpp"
|
||||
#define SDD1_CPP
|
||||
namespace SNES {
|
||||
|
||||
SDD1 sdd1;
|
||||
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {}
|
||||
@@ -11,7 +13,7 @@ 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);
|
||||
cpu_mmio[i & 0x7f] = memory::mmio.mmio[i - 0x2000];
|
||||
memory::mmio.map(i, *this);
|
||||
}
|
||||
|
||||
@@ -156,3 +158,5 @@ SDD1::SDD1() {
|
||||
SDD1::~SDD1() {
|
||||
delete[] buffer.data;
|
||||
}
|
||||
|
||||
};
|
||||
|
65
src/chip/sgb/sgb.cpp
Normal file
65
src/chip/sgb/sgb.cpp
Normal 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
27
src/chip/sgb/sgb.hpp
Normal 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;
|
@@ -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() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -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() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
#define ST010_CPP
|
||||
|
||||
#include "st010.hpp"
|
||||
#define ST010_CPP
|
||||
namespace SNES {
|
||||
|
||||
ST010 st010;
|
||||
|
||||
#include "st010_data.hpp"
|
||||
#include "st010_op.cpp"
|
||||
|
||||
@@ -85,3 +88,5 @@ void ST010::write(unsigned addr, uint8 data) {
|
||||
ram[0x0021] &= ~0x80;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
92
src/chip/superfx/bus/bus.cpp
Normal file
92
src/chip/superfx/bus/bus.cpp
Normal 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
|
27
src/chip/superfx/bus/bus.hpp
Normal file
27
src/chip/superfx/bus/bus.hpp
Normal 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);
|
||||
};
|
121
src/chip/superfx/core/core.cpp
Normal file
121
src/chip/superfx/core/core.cpp
Normal 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
|
93
src/chip/superfx/core/core.hpp
Normal file
93
src/chip/superfx/core/core.hpp
Normal 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();
|
270
src/chip/superfx/core/opcode_table.cpp
Normal file
270
src/chip/superfx/core/opcode_table.cpp
Normal 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
|
661
src/chip/superfx/core/opcodes.cpp
Normal file
661
src/chip/superfx/core/opcodes.cpp
Normal 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 = ®s.r[n];
|
||||
} else {
|
||||
regs.r[n] = regs.sr();
|
||||
regs.reset();
|
||||
}
|
||||
}
|
||||
|
||||
//$20-2f: with rN
|
||||
template<int n> void SuperFX::op_with_r() {
|
||||
regs.sreg = ®s.r[n];
|
||||
regs.dreg = ®s.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 = ®s.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
|
177
src/chip/superfx/core/registers.hpp
Normal file
177
src/chip/superfx/core/registers.hpp
Normal 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];
|
275
src/chip/superfx/disasm/disasm.cpp
Normal file
275
src/chip/superfx/disasm/disasm.cpp
Normal 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
|
5
src/chip/superfx/disasm/disasm.hpp
Normal file
5
src/chip/superfx/disasm/disasm.hpp
Normal 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);
|
67
src/chip/superfx/memory/memory.cpp
Normal file
67
src/chip/superfx/memory/memory.cpp
Normal 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;
|
||||
}
|
||||
}
|
9
src/chip/superfx/memory/memory.hpp
Normal file
9
src/chip/superfx/memory/memory.hpp
Normal 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();
|
118
src/chip/superfx/mmio/mmio.cpp
Normal file
118
src/chip/superfx/mmio/mmio.cpp
Normal 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
|
2
src/chip/superfx/mmio/mmio.hpp
Normal file
2
src/chip/superfx/mmio/mmio.hpp
Normal file
@@ -0,0 +1,2 @@
|
||||
uint8_t mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8_t data);
|
61
src/chip/superfx/superfx.cpp
Normal file
61
src/chip/superfx/superfx.cpp
Normal 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();
|
||||
}
|
||||
|
||||
};
|
20
src/chip/superfx/superfx.hpp
Normal file
20
src/chip/superfx/superfx.hpp
Normal 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;
|
72
src/chip/superfx/timing/timing.cpp
Normal file
72
src/chip/superfx/timing/timing.cpp
Normal 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;
|
||||
}
|
18
src/chip/superfx/timing/timing.hpp
Normal file
18
src/chip/superfx/timing/timing.hpp
Normal 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();
|
@@ -1 +1 @@
|
||||
@mingw32-make platform=win compiler=mingw32-gcc clean
|
||||
@mingw32-make clean
|
||||
|
@@ -1 +0,0 @@
|
||||
make platform=x compiler=gcc clean
|
@@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#ifdef CPUCORE_CPP
|
||||
|
||||
inline void CPUcore::op_adc_b() {
|
||||
int r;
|
||||
if(regs.p.d) {
|
||||
@@ -363,3 +365,5 @@ inline void CPUcore::op_tsb_w() {
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
rd.w |= regs.a.w;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -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
|
||||
|
@@ -73,8 +73,7 @@ struct regs_t {
|
||||
|
||||
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) {}
|
||||
regs_t() : db(0), e(false), irq(false), wai(false), mdr(0) {}
|
||||
};
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#include <../base.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = snes.config.cpu.version;
|
||||
cpu_version = config.cpu.version;
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
@@ -13,3 +15,5 @@ CPU::CPU() {
|
||||
|
||||
CPU::~CPU() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -270,4 +270,4 @@ void sCPU::dma_reset() {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef SCPU_CPP
|
||||
#endif
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -1,7 +1,9 @@
|
||||
#include <../base.hpp>
|
||||
#define SCPU_CPP
|
||||
|
||||
#include <nall/priorityqueue.hpp>
|
||||
|
||||
#define SCPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
|
||||
|
||||
#include "dma/dma.cpp"
|
||||
@@ -12,10 +14,6 @@ priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
|
||||
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) {
|
||||
@@ -98,3 +96,5 @@ sCPU::sCPU() {
|
||||
|
||||
sCPU::~sCPU() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -9,8 +9,6 @@ public:
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
enum DmaState { DmaInactive, DmaRun, DmaCpuSync };
|
||||
|
||||
struct {
|
||||
bool interrupt_pending;
|
||||
uint16 interrupt_vector;
|
||||
@@ -36,12 +34,12 @@ public:
|
||||
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
|
||||
DmaState dma_state;
|
||||
|
||||
//MMIO
|
||||
|
||||
|
@@ -3,8 +3,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 = snes.input.port_read(0);
|
||||
uint8 port1 = snes.input.port_read(1);
|
||||
uint8 port0 = input.port_read(0);
|
||||
uint8 port1 = input.port_read(1);
|
||||
|
||||
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
|
||||
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -18,9 +18,8 @@
|
||||
void add_clocks(unsigned clocks);
|
||||
void scanline();
|
||||
|
||||
alwaysinline void precycle_edge();
|
||||
alwaysinline void cycle_edge();
|
||||
void last_cycle();
|
||||
alwaysinline void last_cycle();
|
||||
|
||||
void timing_power();
|
||||
void timing_reset();
|
||||
|
@@ -5,15 +5,19 @@
|
||||
|
||||
<h1>bsnes™ Usage Documentation</h1><br>
|
||||
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that strives to provide
|
||||
the most faithful emulation experience possible. It focuses on accuracy and
|
||||
clean code; over speed and features.
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that strives to provide the
|
||||
most faithful hardware emulation possible. It focuses on accuracy and clean
|
||||
code, rather than speed and special features. It is meant as a reference
|
||||
emulator to document how the underlying hardware works. It is thus very useful
|
||||
for development and research. And while it can be used for general purpose
|
||||
gaming, it will require significantly more powerful hardware than a typical
|
||||
emulator.
|
||||
<hr>
|
||||
|
||||
<h2><u>Modes of Operation</u></h2><br>
|
||||
|
||||
bsnes is capable of running both in its default multi-user mode, as well as
|
||||
in single-user mode.<br>
|
||||
bsnes is capable of running both in its default multi-user mode, as well as in
|
||||
single-user mode.<br>
|
||||
<br>
|
||||
|
||||
In multi-user mode, configuration data is stored inside the user's home
|
||||
@@ -39,16 +43,15 @@ configuration data.
|
||||
|
||||
<h2><u>Known Limitations</u></h2><br>
|
||||
|
||||
<b>Cartridge co-processors:</b> certain cartridges contain special co-processor chips to enhance
|
||||
their functionality. Some of these are either partially or completely unsupported. A message box
|
||||
warning will pop up when attempting to load such a cartridge.<br>
|
||||
<b>Satellaview BS-X emulation:</b> this hardware is only partially supported.
|
||||
This is mostly because the satellite network it used (St. GIGA) has been shut
|
||||
down. Access to this network would be required to properly reverse engineer much
|
||||
of the hardware. Working around this would require game-specific hacks, which
|
||||
are contrary to the design goals of this emulator. As a result, most BS-X
|
||||
software will not function correctly.<br>
|
||||
<br>
|
||||
|
||||
<b>Satellaview BS-X emulation:</b> this hardware is only partially supported. As a result,
|
||||
most BS-X software will not function correctly.<br>
|
||||
<br>
|
||||
|
||||
<b>Savestates:</b> due to the design of bsnes, it is not plausible to
|
||||
<b>Savestates:</b> due to the internal design of bsnes, it is not plausible to
|
||||
implement support for savestate and/or rewind functionality.<br>
|
||||
<br>
|
||||
|
||||
@@ -58,6 +61,7 @@ implement support for savestate and/or rewind functionality.<br>
|
||||
<h2><u>Contributors</u></h2>
|
||||
• Andreas Naive<br>
|
||||
• anomie<br>
|
||||
• _Demo_<br>
|
||||
• Derrick Sobodash<br>
|
||||
• DMV27<br>
|
||||
• FirebrandX<br>
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#include <../base.hpp>
|
||||
|
||||
#define ADSP_CPP
|
||||
namespaec SNES {
|
||||
|
||||
#include "adsp_tables.cpp"
|
||||
|
||||
@@ -580,10 +582,12 @@ int32 fir_samplel, fir_sampler;
|
||||
msampler = sclamp<16>(msampler);
|
||||
}
|
||||
|
||||
snes.audio.update(msamplel, msampler);
|
||||
audio.sample(msamplel, msampler);
|
||||
scheduler.addclocks_dsp(32 * 3 * 8);
|
||||
scheduler.sync_dspsmp();
|
||||
}
|
||||
|
||||
aDSP::aDSP() {}
|
||||
aDSP::~aDSP() {}
|
||||
|
||||
};
|
||||
|
@@ -74,4 +74,4 @@ const int16 aDSP::gaussian_table[512] = {
|
||||
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||
};
|
||||
|
||||
#endif //ifdef ADSP_CPP
|
||||
#endif
|
||||
|
@@ -59,4 +59,4 @@ void sDSP::brr_decode(voice_t &v) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -49,4 +49,4 @@ inline bool sDSP::counter_poll(unsigned rate) {
|
||||
return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0;
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -106,7 +106,7 @@ void sDSP::echo_27() {
|
||||
}
|
||||
|
||||
//output sample to DAC
|
||||
snes.audio.update(outl, outr);
|
||||
audio.sample(outl, outr);
|
||||
}
|
||||
|
||||
void sDSP::echo_28() {
|
||||
@@ -132,4 +132,4 @@ void sDSP::echo_30() {
|
||||
echo_write(1);
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -59,4 +59,4 @@ void sDSP::envelope_run(voice_t &v) {
|
||||
if(counter_poll(rate) == true) v.env = env;
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -51,4 +51,4 @@ int sDSP::gaussian_interpolate(const voice_t &v) {
|
||||
return sclamp<16>(output) & ~1;
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -32,4 +32,4 @@ void sDSP::misc_30() {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
S-DSP emulator
|
||||
license: LGPLv2
|
||||
|
||||
Note: this is basically a C++ cothreaded implementation of Shay Green's (blargg's) S-DSP emulator.
|
||||
The actual algorithms, timing information, tables, variable names, etc were all from him.
|
||||
*/
|
||||
|
||||
#include <../base.hpp>
|
||||
|
||||
#define SDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#define REG(n) state.regs[r_##n]
|
||||
#define VREG(n) state.regs[v.vidx + v_##n]
|
||||
|
||||
#if !defined(USE_STATE_MACHINE)
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
#define phase_start() while(true) {
|
||||
#define phase(n)
|
||||
#define tick() scheduler.addclocks_dsp(3 * 8); scheduler.sync_dspsmp()
|
||||
@@ -324,3 +324,5 @@ sDSP::sDSP() {
|
||||
|
||||
sDSP::~sDSP() {
|
||||
}
|
||||
|
||||
};
|
||||
|
@@ -171,4 +171,4 @@ void sDSP::voice_9(voice_t &v) {
|
||||
VREG(envx) = (uint8)state.envx_buf;
|
||||
}
|
||||
|
||||
#endif //ifdef SDSP_CPP
|
||||
#endif
|
||||
|
@@ -1,25 +1,30 @@
|
||||
#include "cheat/cheat.hpp"
|
||||
namespace SNES {
|
||||
#include "cheat/cheat.hpp"
|
||||
|
||||
#include "memory/memory.hpp"
|
||||
#include "memory/smemory/smemory.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "memory/smemory/smemory.hpp"
|
||||
|
||||
#include "cpu/cpu.hpp"
|
||||
#include "cpu/core/core.hpp"
|
||||
#include "cpu/scpu/scpu.hpp"
|
||||
#include "cpu/cpu.hpp"
|
||||
#include "cpu/core/core.hpp"
|
||||
#include "cpu/scpu/scpu.hpp"
|
||||
|
||||
#include "ppu/ppu.hpp"
|
||||
#include "ppu/bppu/bppu.hpp"
|
||||
#include "smp/smp.hpp"
|
||||
#include "smp/core/core.hpp"
|
||||
#include "smp/ssmp/ssmp.hpp"
|
||||
|
||||
#include "smp/smp.hpp"
|
||||
#include "smp/ssmp/ssmp.hpp"
|
||||
#include "ppu/ppu.hpp"
|
||||
#include "ppu/bppu/bppu.hpp"
|
||||
|
||||
#include "dsp/dsp.hpp"
|
||||
#include "dsp/sdsp/sdsp.hpp"
|
||||
#include "dsp/dsp.hpp"
|
||||
#include "dsp/sdsp/sdsp.hpp"
|
||||
|
||||
extern BUSCORE bus;
|
||||
extern CPUCORE cpu;
|
||||
extern SMPCORE smp;
|
||||
extern DSPCORE dsp;
|
||||
extern PPUCORE ppu;
|
||||
extern BUSCORE bus;
|
||||
extern CPUCORE cpu;
|
||||
extern SMPCORE smp;
|
||||
extern DSPCORE dsp;
|
||||
extern PPUCORE ppu;
|
||||
|
||||
#include "snes/snes.hpp"
|
||||
#include "system/system.hpp"
|
||||
#include "chip/chip.hpp"
|
||||
#include "cartridge/cartridge.hpp"
|
||||
};
|
||||
|
@@ -1,8 +1,13 @@
|
||||
DirectFilter filter_direct;
|
||||
|
||||
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
outwidth = width;
|
||||
outheight = height;
|
||||
}
|
||||
|
||||
void DirectFilter::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
pitch >>= 1;
|
||||
outpitch >>= 2;
|
||||
@@ -24,7 +29,4 @@ void DirectFilter::render(
|
||||
input += pitch - width;
|
||||
output += outpitch - width;
|
||||
}
|
||||
|
||||
outwidth = width;
|
||||
outheight = height;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
class DirectFilter : public Filter {
|
||||
public:
|
||||
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
};
|
||||
|
||||
extern DirectFilter filter_direct;
|
||||
|
@@ -4,30 +4,26 @@ void FilterInterface::set(FilterInterface::FilterType type) {
|
||||
active_filter = type;
|
||||
}
|
||||
|
||||
void FilterInterface::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
switch(active_filter) { default:
|
||||
case Direct: return filter_direct.size(outwidth, outheight, width, height);
|
||||
case Scanline: return filter_scanline.size(outwidth, outheight, width, height);
|
||||
case Scale2x: return filter_scale2x.size(outwidth, outheight, width, height);
|
||||
case HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
|
||||
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void FilterInterface::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
switch(active_filter) { default:
|
||||
case Direct: {
|
||||
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
} break;
|
||||
|
||||
case Scanline: {
|
||||
filter_scanline.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
} break;
|
||||
|
||||
case Scale2x: {
|
||||
filter_scale2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
} break;
|
||||
|
||||
case HQ2x: {
|
||||
filter_hq2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
} break;
|
||||
|
||||
case NTSC: {
|
||||
filter_ntsc.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
} break;
|
||||
case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
||||
case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
|
||||
case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
|
||||
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
|
||||
case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
class Filter {
|
||||
public:
|
||||
virtual void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) = 0;
|
||||
|
||||
virtual void render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) = 0;
|
||||
};
|
||||
|
||||
@@ -18,9 +20,11 @@ public:
|
||||
|
||||
void set(FilterType type);
|
||||
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
|
||||
void render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
);
|
||||
|
||||
FilterInterface();
|
||||
|
@@ -56,12 +56,17 @@ static uint16_t blend10(uint32_t c1, uint32_t c2, uint32_t c3) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
outwidth = width * 2;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
||||
void HQ2xFilter::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
if(width > 256 || height > 240) {
|
||||
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,9 +130,6 @@ void HQ2xFilter::render(
|
||||
|
||||
memset(out0, 0, 2048);
|
||||
memset(out1, 0, 2048);
|
||||
|
||||
outwidth = width * 2;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
||||
HQ2xFilter::HQ2xFilter() {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
class HQ2xFilter : public Filter {
|
||||
public:
|
||||
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
|
||||
HQ2xFilter();
|
||||
~HQ2xFilter();
|
||||
|
@@ -11,4 +11,4 @@ namespace libfilter {
|
||||
#include "scale2x.cpp"
|
||||
#include "hq2x.cpp"
|
||||
#include "ntsc.cpp"
|
||||
} //namespace libfilter
|
||||
}
|
||||
|
@@ -17,6 +17,6 @@ namespace libfilter {
|
||||
#include "scale2x.hpp"
|
||||
#include "hq2x.hpp"
|
||||
#include "ntsc.hpp"
|
||||
} //namespace libfilter
|
||||
};
|
||||
|
||||
#endif //ifndef LIBFILTER_H
|
||||
#endif
|
||||
|
@@ -2,37 +2,42 @@
|
||||
|
||||
NTSCFilter filter_ntsc;
|
||||
|
||||
void NTSCFilter::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
if(!ntsc)return;
|
||||
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
outwidth = SNES_NTSC_OUT_WIDTH(256);
|
||||
outheight = height;
|
||||
}
|
||||
|
||||
int const out_width = outwidth = SNES_NTSC_OUT_WIDTH(256);
|
||||
int const out_height = outheight = height;
|
||||
void NTSCFilter::render(
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
if(!ntsc) return;
|
||||
|
||||
width = SNES_NTSC_OUT_WIDTH(256);
|
||||
burst ^= burst_toggle;
|
||||
|
||||
//blit multiple scanlines of same width, rather than one at a time
|
||||
int run_start = 0;
|
||||
int run_width = line[0];
|
||||
int l = 0;
|
||||
pitch >>= 1;
|
||||
outpitch >>= 2;
|
||||
|
||||
while(1) {
|
||||
if(run_width != line[l] || l >= out_height) {
|
||||
uint16_t const *in = (uint16_t*)((uint8_t*)input + pitch * run_start);
|
||||
uint16_t *out = (uint16_t*)((uint8_t*)output + outpitch * run_start);
|
||||
int height = l - run_start;
|
||||
int line_burst = (burst + run_start) % 3;
|
||||
if(run_width == 256) {
|
||||
snes_ntsc_blit(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch);
|
||||
unsigned line_burst = burst;
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint16_t *in = input + y * pitch;
|
||||
uint32_t *out = output + y * outpitch;
|
||||
|
||||
//render as many lines in one snes_ntsc_blit as possible:
|
||||
//do this by determining for how many lines the width stays the same
|
||||
unsigned rheight = 1;
|
||||
unsigned rwidth = line[y];
|
||||
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
|
||||
|
||||
if(rwidth == 256) {
|
||||
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
||||
} else {
|
||||
snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch);
|
||||
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
||||
}
|
||||
if(l >= out_height) break;
|
||||
run_width = line[l];
|
||||
run_start = l;
|
||||
}
|
||||
l++;
|
||||
|
||||
line_burst = (line_burst + rheight) % 3;
|
||||
y += rheight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +59,8 @@ void NTSCFilter::adjust(
|
||||
if(!ntsc) {
|
||||
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
|
||||
if(!ntsc) {
|
||||
return; //to do: report out of memory error
|
||||
fprintf(stderr, "error: snes_ntsc: out of memory\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
class NTSCFilter : public Filter {
|
||||
public:
|
||||
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields);
|
||||
|
||||
NTSCFilter();
|
||||
|
@@ -1,11 +1,16 @@
|
||||
Scale2xFilter filter_scale2x;
|
||||
|
||||
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
outwidth = width * 2;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
||||
void Scale2xFilter::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
if(width > 256 || height > 240) {
|
||||
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,7 +46,4 @@ void Scale2xFilter::render(
|
||||
input += pitch - 256;
|
||||
output += outpitch + outpitch - 512;
|
||||
}
|
||||
|
||||
outwidth = width * 2;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
class Scale2xFilter : public Filter {
|
||||
public:
|
||||
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
};
|
||||
|
||||
extern Scale2xFilter filter_scale2x;
|
||||
|
@@ -1,11 +1,16 @@
|
||||
ScanlineFilter filter_scanline;
|
||||
|
||||
void ScanlineFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||||
outwidth = width;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
||||
void ScanlineFilter::render(
|
||||
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight,
|
||||
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height
|
||||
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
|
||||
unsigned *line, unsigned width, unsigned height
|
||||
) {
|
||||
if(height > 240) {
|
||||
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
|
||||
filter_direct.render(output, outpitch, input, pitch, line, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +19,7 @@ void ScanlineFilter::render(
|
||||
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t *out0 = output;
|
||||
uint32_t *out1 = output + pitch;
|
||||
uint32_t *out1 = output + outpitch;
|
||||
if(width == 512 && line[y] == 256) {
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
uint16_t p = *input++;
|
||||
@@ -34,7 +39,4 @@ void ScanlineFilter::render(
|
||||
input += pitch - width;
|
||||
output += outpitch * 2;
|
||||
}
|
||||
|
||||
outwidth = width;
|
||||
outheight = height * 2;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
class ScanlineFilter : public Filter {
|
||||
public:
|
||||
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
|
||||
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
|
||||
};
|
||||
|
||||
extern ScanlineFilter filter_scanline;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user