o add bsnes
This commit is contained in:
parent
bcb4a055e9
commit
27b58a09f2
278
bsnes/Makefile
Executable file
278
bsnes/Makefile
Executable file
@ -0,0 +1,278 @@
|
|||||||
|
include lib/nall/Makefile.string
|
||||||
|
prefix = /usr/local
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
##########
|
||||||
|
### os ###
|
||||||
|
##########
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
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)
|
||||||
|
else
|
||||||
|
unknown_platform: help;
|
||||||
|
endif
|
||||||
|
|
||||||
|
############
|
||||||
|
### ruby ###
|
||||||
|
############
|
||||||
|
|
||||||
|
rubyflags = $(if $(findstring .sdl,$(ruby)),`sdl-config --cflags`)
|
||||||
|
link += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
####################
|
||||||
|
### core objects ###
|
||||||
|
####################
|
||||||
|
|
||||||
|
objects = libco ruby libfilter string \
|
||||||
|
reader cart cheat \
|
||||||
|
memory smemory cpu scpu smp ssmp sdsp ppu bppu snes \
|
||||||
|
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)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(enable_jma),true)
|
||||||
|
objects += jma jcrc32 lzmadec 7zlzma iiostrm inbyte lzma winout
|
||||||
|
flags += $(call mkdef,JMA_SUPPORT)
|
||||||
|
endif
|
||||||
|
|
||||||
|
######################
|
||||||
|
### implicit rules ###
|
||||||
|
######################
|
||||||
|
|
||||||
|
compile = \
|
||||||
|
$(strip \
|
||||||
|
$(if $(filter %.c,$<), \
|
||||||
|
$(c) $(flags) $1 $(rule), \
|
||||||
|
$(if $(filter %.cpp,$<), \
|
||||||
|
$(cpp) $(flags) $1 $(rule) \
|
||||||
|
) \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
%.$(obj): $<; $(call compile)
|
||||||
|
|
||||||
|
all: build;
|
||||||
|
|
||||||
|
include $(ui)/Makefile
|
||||||
|
objects := $(patsubst %,obj/%.$(obj),$(objects))
|
||||||
|
rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),$(call mkdef,$c))
|
||||||
|
|
||||||
|
#################
|
||||||
|
### libraries ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
obj/ruby.$(obj): lib/ruby/ruby.cpp lib/ruby/* lib/ruby/video/* lib/ruby/audio/* lib/ruby/input/*
|
||||||
|
$(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/*
|
||||||
|
|
||||||
|
#################
|
||||||
|
### utilities ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
obj/reader.$(obj): reader/reader.cpp reader/*
|
||||||
|
obj/cart.$(obj) : cart/cart.cpp cart/*
|
||||||
|
obj/cheat.$(obj) : cheat/cheat.cpp cheat/*
|
||||||
|
|
||||||
|
##############
|
||||||
|
### memory ###
|
||||||
|
##############
|
||||||
|
|
||||||
|
obj/memory.$(obj) : memory/memory.cpp memory/*
|
||||||
|
obj/smemory.$(obj): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/mapper/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
### cpu ###
|
||||||
|
###########
|
||||||
|
|
||||||
|
obj/cpu.$(obj) : cpu/cpu.cpp cpu/*
|
||||||
|
obj/scpu.$(obj): cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/core/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
### 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/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
### dsp ###
|
||||||
|
###########
|
||||||
|
|
||||||
|
obj/adsp.$(obj): dsp/adsp/adsp.cpp dsp/adsp/*
|
||||||
|
obj/sdsp.$(obj): dsp/sdsp/sdsp.cpp dsp/sdsp/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
### ppu ###
|
||||||
|
###########
|
||||||
|
|
||||||
|
obj/ppu.$(obj) : ppu/ppu.cpp ppu/*
|
||||||
|
obj/bppu.$(obj): ppu/bppu/bppu.cpp ppu/bppu/*
|
||||||
|
|
||||||
|
############
|
||||||
|
### snes ###
|
||||||
|
############
|
||||||
|
|
||||||
|
obj/snes.$(obj): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/*
|
||||||
|
|
||||||
|
#####################
|
||||||
|
### special chips ###
|
||||||
|
#####################
|
||||||
|
|
||||||
|
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/*
|
||||||
|
|
||||||
|
############
|
||||||
|
### 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/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
### jma ###
|
||||||
|
###########
|
||||||
|
|
||||||
|
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/*
|
||||||
|
|
||||||
|
###############
|
||||||
|
### targets ###
|
||||||
|
###############
|
||||||
|
|
||||||
|
build: ui_build $(objects)
|
||||||
|
$(strip $(cpp) $(call mkbin,../bsnes) $(objects) $(link))
|
||||||
|
|
||||||
|
install:
|
||||||
|
install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes
|
||||||
|
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||||
|
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||||
|
|
||||||
|
clean: ui_clean
|
||||||
|
-@$(call delete,obj/*.$(obj))
|
||||||
|
-@$(call delete,*.res)
|
||||||
|
-@$(call delete,*.pgd)
|
||||||
|
-@$(call delete,*.pgc)
|
||||||
|
-@$(call delete,*.ilk)
|
||||||
|
-@$(call delete,*.pdb)
|
||||||
|
-@$(call delete,*.manifest)
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Usage: $(MAKE) platform=(os) compiler=(cc) [options]"
|
||||||
|
@echo ""
|
||||||
|
@echo "Supported platforms:"
|
||||||
|
@echo " x - Linux / BSD (x86, x86-64)"
|
||||||
|
@echo " win - Windows (x86, x86-64)"
|
||||||
|
@echo ""
|
||||||
|
@echo "Supported compilers:"
|
||||||
|
@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)"
|
||||||
|
@echo " enable_jma=[true|false] - Enable JMA support (default=false)"
|
||||||
|
@echo ""
|
||||||
|
@echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true"
|
||||||
|
@echo ""
|
||||||
49
bsnes/base.hpp
Executable file
49
bsnes/base.hpp
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#define BSNES_VERSION "0.042"
|
||||||
|
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||||
|
|
||||||
|
#define BUSCORE sBus
|
||||||
|
#define CPUCORE sCPU
|
||||||
|
#define SMPCORE sSMP
|
||||||
|
#define DSPCORE sDSP
|
||||||
|
#define PPUCORE bPPU
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
||||||
|
//game genie + pro action replay code support (~2% speed hit)
|
||||||
|
#define CHEAT_SYSTEM
|
||||||
|
|
||||||
|
#include <libco/libco.h>
|
||||||
|
|
||||||
|
#include <nall/algorithm.hpp>
|
||||||
|
#include <nall/array.hpp>
|
||||||
|
#include <nall/bit.hpp>
|
||||||
|
#include <nall/detect.hpp>
|
||||||
|
#include <nall/endian.hpp>
|
||||||
|
#include <nall/file.hpp>
|
||||||
|
#include <nall/moduloarray.hpp>
|
||||||
|
#include <nall/new.hpp>
|
||||||
|
#include <nall/platform.hpp>
|
||||||
|
#include <nall/property.hpp>
|
||||||
|
#include <nall/stdint.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
#include <nall/utility.hpp>
|
||||||
|
#include <nall/vector.hpp>
|
||||||
|
using namespace nall;
|
||||||
|
|
||||||
|
typedef int8_t int8;
|
||||||
|
typedef int16_t int16;
|
||||||
|
typedef int32_t int32;
|
||||||
|
typedef int64_t int64;
|
||||||
|
typedef uint8_t uint8;
|
||||||
|
typedef uint16_t uint16;
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
|
||||||
|
#include "interface.hpp"
|
||||||
BIN
bsnes/bsnes.lnk
Executable file
BIN
bsnes/bsnes.lnk
Executable file
Binary file not shown.
234
bsnes/cart/cart.cpp
Executable file
234
bsnes/cart/cart.cpp
Executable file
@ -0,0 +1,234 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
178
bsnes/cart/cart.hpp
Executable file
178
bsnes/cart/cart.hpp
Executable file
@ -0,0 +1,178 @@
|
|||||||
|
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,
|
||||||
|
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;
|
||||||
109
bsnes/cart/cart_file.cpp
Executable file
109
bsnes/cart/cart_file.cpp
Executable file
@ -0,0 +1,109 @@
|
|||||||
|
#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
|
||||||
272
bsnes/cart/cart_header.cpp
Executable file
272
bsnes/cart/cart_header.cpp
Executable file
@ -0,0 +1,272 @@
|
|||||||
|
#ifdef CART_CPP
|
||||||
|
|
||||||
|
void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const {
|
||||||
|
info.reset();
|
||||||
|
unsigned index = find_header(data, size);
|
||||||
|
|
||||||
|
//=======================
|
||||||
|
//detect BS-X flash carts
|
||||||
|
//=======================
|
||||||
|
|
||||||
|
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
|
||||||
|
if(data[index + 0x14] == 0x00) {
|
||||||
|
const uint8_t n15 = data[index + 0x15];
|
||||||
|
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
|
||||||
|
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
|
||||||
|
info.type = TypeBsx;
|
||||||
|
info.mapper = BSXROM;
|
||||||
|
info.region = NTSC; //BS-X only released in Japan
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================
|
||||||
|
//detect Sufami Turbo carts
|
||||||
|
//=========================
|
||||||
|
|
||||||
|
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
|
||||||
|
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
|
||||||
|
info.type = TypeSufamiTurboBios;
|
||||||
|
} else {
|
||||||
|
info.type = TypeSufamiTurbo;
|
||||||
|
}
|
||||||
|
info.mapper = STROM;
|
||||||
|
info.region = NTSC; //Sufami Turbo only released in Japan
|
||||||
|
return; //RAM size handled internally by load_cart_st();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=====================
|
||||||
|
//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') {
|
||||||
|
uint8 n13 = data[index - 13];
|
||||||
|
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
|
||||||
|
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
|
||||||
|
info.bsx_slot = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info.bsx_slot == true) {
|
||||||
|
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
|
||||||
|
//BS-X base cart
|
||||||
|
info.type = TypeBsxBios;
|
||||||
|
info.mapper = BSXROM;
|
||||||
|
info.region = NTSC; //BS-X only released in Japan
|
||||||
|
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
|
||||||
|
} else {
|
||||||
|
info.type = TypeBsxSlotted;
|
||||||
|
info.mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//standard cart
|
||||||
|
info.type = TypeNormal;
|
||||||
|
|
||||||
|
if(index == 0x7fc0 && size >= 0x401000) {
|
||||||
|
info.mapper = ExLoROM;
|
||||||
|
} else if(index == 0x7fc0 && mapper == 0x32) {
|
||||||
|
info.mapper = ExLoROM;
|
||||||
|
} else if(index == 0x7fc0) {
|
||||||
|
info.mapper = LoROM;
|
||||||
|
} else if(index == 0xffc0) {
|
||||||
|
info.mapper = HiROM;
|
||||||
|
} else { //index == 0x40ffc0
|
||||||
|
info.mapper = ExHiROM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
|
||||||
|
info.superfx = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x23 && (rom_type == 0x34 || rom_type == 0x35)) {
|
||||||
|
info.sa1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x35 && rom_type == 0x55) {
|
||||||
|
info.srtc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
|
||||||
|
info.sdd1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
|
||||||
|
info.spc7110 = true;
|
||||||
|
info.spc7110rtc = (rom_type == 0xf9);
|
||||||
|
info.mapper = SPC7110ROM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x20 && rom_type == 0xf3) {
|
||||||
|
info.cx4 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
|
||||||
|
info.dsp1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
|
||||||
|
info.dsp1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
|
||||||
|
info.dsp1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info.dsp1 == true) {
|
||||||
|
if((mapper & 0x2f) == 0x20 && size <= 0x100000) {
|
||||||
|
info.dsp1_mapper = DSP1LoROM1MB;
|
||||||
|
} else if((mapper & 0x2f) == 0x20) {
|
||||||
|
info.dsp1_mapper = DSP1LoROM2MB;
|
||||||
|
} else if((mapper & 0x2f) == 0x21) {
|
||||||
|
info.dsp1_mapper = DSP1HiROM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x20 && rom_type == 0x05) {
|
||||||
|
info.dsp2 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
|
||||||
|
info.dsp3 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0x03) {
|
||||||
|
info.dsp4 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0x25) {
|
||||||
|
info.obc1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
|
||||||
|
info.st010 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mapper == 0x30 && rom_type == 0xf6 && rom_size < 10) {
|
||||||
|
info.st011 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
unsigned score_lo = score_header(data, size, 0x007fc0);
|
||||||
|
unsigned score_hi = score_header(data, size, 0x00ffc0);
|
||||||
|
unsigned score_ex = score_header(data, size, 0x40ffc0);
|
||||||
|
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
|
||||||
|
|
||||||
|
if(score_lo >= score_hi && score_lo >= score_ex) {
|
||||||
|
return 0x007fc0;
|
||||||
|
} else if(score_hi >= score_ex) {
|
||||||
|
return 0x00ffc0;
|
||||||
|
} else {
|
||||||
|
return 0x40ffc0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Cartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) const {
|
||||||
|
if(size < addr + 64) return 0; //image too small to contain header at this location?
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
uint16 resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
|
||||||
|
uint16 checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
|
||||||
|
uint16 complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
|
||||||
|
|
||||||
|
uint8 resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
|
||||||
|
uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
|
||||||
|
|
||||||
|
//$00:[000-7fff] contains uninitialized RAM and MMIO.
|
||||||
|
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
|
||||||
|
if(resetvector < 0x8000) return 0;
|
||||||
|
|
||||||
|
//some images duplicate the header in multiple locations, and others have completely
|
||||||
|
//invalid header information that cannot be relied upon.
|
||||||
|
//below code will analyze the first opcode executed at the specified reset vector to
|
||||||
|
//determine the probability that this is the correct header.
|
||||||
|
|
||||||
|
//most likely opcodes
|
||||||
|
if(resetop == 0x78 //sei
|
||||||
|
|| resetop == 0x18 //clc (clc; xce)
|
||||||
|
|| resetop == 0x38 //sec (sec; xce)
|
||||||
|
|| resetop == 0x9c //stz $nnnn (stz $4200)
|
||||||
|
|| resetop == 0x4c //jmp $nnnn
|
||||||
|
|| resetop == 0x5c //jml $nnnnnn
|
||||||
|
) score += 8;
|
||||||
|
|
||||||
|
//plausible opcodes
|
||||||
|
if(resetop == 0xc2 //rep #$nn
|
||||||
|
|| resetop == 0xe2 //sep #$nn
|
||||||
|
|| resetop == 0xad //lda $nnnn
|
||||||
|
|| resetop == 0xae //ldx $nnnn
|
||||||
|
|| resetop == 0xac //ldy $nnnn
|
||||||
|
|| resetop == 0xaf //lda $nnnnnn
|
||||||
|
|| resetop == 0xa9 //lda #$nn
|
||||||
|
|| resetop == 0xa2 //ldx #$nn
|
||||||
|
|| resetop == 0xa0 //ldy #$nn
|
||||||
|
|| resetop == 0x20 //jsr $nnnn
|
||||||
|
|| resetop == 0x22 //jsl $nnnnnn
|
||||||
|
) score += 4;
|
||||||
|
|
||||||
|
//implausible opcodes
|
||||||
|
if(resetop == 0x40 //rti
|
||||||
|
|| resetop == 0x60 //rts
|
||||||
|
|| resetop == 0x6b //rtl
|
||||||
|
|| resetop == 0xcd //cmp $nnnn
|
||||||
|
|| resetop == 0xec //cpx $nnnn
|
||||||
|
|| resetop == 0xcc //cpy $nnnn
|
||||||
|
) score -= 4;
|
||||||
|
|
||||||
|
//least likely opcodes
|
||||||
|
if(resetop == 0x00 //brk #$nn
|
||||||
|
|| resetop == 0x02 //cop #$nn
|
||||||
|
|| resetop == 0xdb //stp
|
||||||
|
|| resetop == 0x42 //wdm
|
||||||
|
|| resetop == 0xff //sbc $nnnnnn,x
|
||||||
|
) score -= 8;
|
||||||
|
|
||||||
|
//at times, both the header and reset vector's first opcode will match ...
|
||||||
|
//fallback and rely on info validity in these cases to determine more likely header.
|
||||||
|
|
||||||
|
//a valid checksum is the biggest indicator of a valid header.
|
||||||
|
if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
|
||||||
|
|
||||||
|
if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
|
||||||
|
if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
|
||||||
|
if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
|
||||||
|
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
|
||||||
|
|
||||||
|
if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
|
||||||
|
if(data[addr + RomType] < 0x08) score++;
|
||||||
|
if(data[addr + RomSize] < 0x10) score++;
|
||||||
|
if(data[addr + RamSize] < 0x08) score++;
|
||||||
|
if(data[addr + CartRegion] < 14) score++;
|
||||||
|
|
||||||
|
if(score < 0) score = 0;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
244
bsnes/cart/cart_loader.cpp
Executable file
244
bsnes/cart/cart_loader.cpp
Executable file
@ -0,0 +1,244 @@
|
|||||||
|
#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;
|
||||||
|
if(load_file(get_filename(filename, "ups", snes.config.path.patch), pdata, psize, CompressionInspect) == true) {
|
||||||
|
apply_patch(pdata, psize, data, size);
|
||||||
|
delete[] pdata;
|
||||||
|
patched = true;
|
||||||
|
} 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
|
||||||
3
bsnes/cc.bat
Executable file
3
bsnes/cc.bat
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
::@mingw32-make platform=win compiler=mingw32-gcc
|
||||||
|
@mingw32-make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true
|
||||||
|
@pause
|
||||||
2
bsnes/cc.sh
Executable file
2
bsnes/cc.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
make platform=x compiler=gcc
|
||||||
|
#make platform=x compiler=gcc enable_gzip=true enable_jma=true
|
||||||
392
bsnes/cheat/cheat.cpp
Executable file
392
bsnes/cheat/cheat.cpp
Executable file
@ -0,0 +1,392 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
|
||||||
|
Cheat cheat;
|
||||||
|
|
||||||
|
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
|
||||||
|
enabled = source.enabled;
|
||||||
|
code = source.code;
|
||||||
|
desc = source.desc;
|
||||||
|
count = source.count;
|
||||||
|
|
||||||
|
addr.reset();
|
||||||
|
data.reset();
|
||||||
|
for(unsigned n = 0; n < count; n++) {
|
||||||
|
addr[n] = source.addr[n];
|
||||||
|
data[n] = source.data[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//used to sort cheat code list by description
|
||||||
|
bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
|
||||||
|
return strcmp(desc, source.desc) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//parse item ("0123-4567+89AB-CDEF"), return cheat_t item
|
||||||
|
//return true if code is valid, false otherwise
|
||||||
|
bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
|
||||||
|
item.enabled = false;
|
||||||
|
item.count = 0;
|
||||||
|
|
||||||
|
lstring list;
|
||||||
|
list.split("+", s);
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < list.size(); n++) {
|
||||||
|
unsigned addr;
|
||||||
|
uint8_t data;
|
||||||
|
type_t type;
|
||||||
|
if(decode(list[n], addr, data, type) == false) return false;
|
||||||
|
|
||||||
|
item.addr[item.count] = addr;
|
||||||
|
item.data[item.count] = data;
|
||||||
|
item.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
|
||||||
|
//returns true if cheat code was found, false if it was not.
|
||||||
|
//when true, cheat code substitution value is stored in data.
|
||||||
|
bool Cheat::read(unsigned addr, uint8_t &data) const {
|
||||||
|
addr = mirror_address(addr);
|
||||||
|
for(unsigned i = 0; i < code.size(); i++) {
|
||||||
|
if(enabled(i) == false) continue;
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < code[i].count; n++) {
|
||||||
|
if(addr == mirror_address(code[i].addr[n])) {
|
||||||
|
data = code[i].data[n];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//code not found, or code is disabled
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//master control
|
||||||
|
//==============
|
||||||
|
|
||||||
|
//global cheat system enable/disable:
|
||||||
|
//if disabled, *all* cheat codes are disabled;
|
||||||
|
//otherwise only individually disabled codes are.
|
||||||
|
|
||||||
|
bool Cheat::enabled() const {
|
||||||
|
return cheat_system_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::enable() {
|
||||||
|
cheat_system_enabled = true;
|
||||||
|
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::disable() {
|
||||||
|
cheat_system_enabled = false;
|
||||||
|
cheat_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================
|
||||||
|
//cheat list manipulation routines
|
||||||
|
//================================
|
||||||
|
|
||||||
|
bool Cheat::add(bool enable, const char *code_, const char *desc_) {
|
||||||
|
cheat_t item;
|
||||||
|
if(decode(code_, item) == false) return false;
|
||||||
|
|
||||||
|
unsigned i = code.size();
|
||||||
|
code[i] = item;
|
||||||
|
code[i].enabled = enable;
|
||||||
|
code[i].desc = desc_;
|
||||||
|
code[i].code = code_;
|
||||||
|
encode_description(code[i].desc);
|
||||||
|
update(code[i]);
|
||||||
|
|
||||||
|
update_cheat_status();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
|
||||||
|
cheat_t item;
|
||||||
|
if(decode(code_, item) == false) return false;
|
||||||
|
|
||||||
|
//disable current code and clear from code lookup table
|
||||||
|
code[i].enabled = false;
|
||||||
|
update(code[i]);
|
||||||
|
|
||||||
|
code[i] = item;
|
||||||
|
code[i].enabled = enable;
|
||||||
|
code[i].desc = desc_;
|
||||||
|
code[i].code = code_;
|
||||||
|
encode_description(code[i].desc);
|
||||||
|
update(code[i]);
|
||||||
|
|
||||||
|
update_cheat_status();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::remove(unsigned i) {
|
||||||
|
unsigned size = code.size();
|
||||||
|
if(i >= size) return false; //also verifies size cannot be < 1
|
||||||
|
|
||||||
|
for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
|
||||||
|
code.resize(size - 1);
|
||||||
|
|
||||||
|
update_cheat_status();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::get(unsigned i, cheat_t &item) const {
|
||||||
|
if(i >= code.size()) return false;
|
||||||
|
|
||||||
|
item = code[i];
|
||||||
|
decode_description(item.desc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================
|
||||||
|
//cheat status modifier routines
|
||||||
|
//==============================
|
||||||
|
|
||||||
|
bool Cheat::enabled(unsigned i) const {
|
||||||
|
return (i < code.size() ? code[i].enabled : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::enable(unsigned i) {
|
||||||
|
if(i >= code.size()) return;
|
||||||
|
|
||||||
|
code[i].enabled = true;
|
||||||
|
update(code[i]);
|
||||||
|
update_cheat_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::disable(unsigned i) {
|
||||||
|
if(i >= code.size()) return;
|
||||||
|
|
||||||
|
code[i].enabled = false;
|
||||||
|
update(code[i]);
|
||||||
|
update_cheat_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
//===============================
|
||||||
|
//cheat file load / save routines
|
||||||
|
//
|
||||||
|
//file format:
|
||||||
|
//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
|
||||||
|
//...
|
||||||
|
//===============================
|
||||||
|
|
||||||
|
bool Cheat::load(const char *fn) {
|
||||||
|
string data;
|
||||||
|
if(!data.readfile(fn)) return false;
|
||||||
|
data.replace("\r\n", "\n");
|
||||||
|
data.qreplace(" ", "");
|
||||||
|
|
||||||
|
lstring line;
|
||||||
|
line.split("\n", data);
|
||||||
|
for(unsigned i = 0; i < line.size(); i++) {
|
||||||
|
lstring part;
|
||||||
|
part.qsplit(",", line[i]);
|
||||||
|
if(part.size() != 3) continue;
|
||||||
|
trim(part[0], "\"");
|
||||||
|
add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::save(const char *fn) const {
|
||||||
|
file fp;
|
||||||
|
if(!fp.open(fn, file::mode_write)) return false;
|
||||||
|
for(unsigned i = 0; i < code.size(); i++) {
|
||||||
|
fp.print(string()
|
||||||
|
<< "\"" << code[i].desc << "\", "
|
||||||
|
<< (code[i].enabled ? "enabled, " : "disabled, ")
|
||||||
|
<< code[i].code << "\r\n");
|
||||||
|
}
|
||||||
|
fp.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::clear() {
|
||||||
|
cheat_enabled_code_exists = false;
|
||||||
|
memset(mask, 0, 0x200000);
|
||||||
|
code.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cheat::Cheat() : cheat_system_enabled(true) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================
|
||||||
|
//internal functions
|
||||||
|
//==================
|
||||||
|
|
||||||
|
//string <> binary code translation routines
|
||||||
|
//decode() "7e123456" -> 0x7e123456
|
||||||
|
//encode() 0x7e123456 -> "7e123456"
|
||||||
|
|
||||||
|
bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
|
||||||
|
string t = s;
|
||||||
|
strlower(t);
|
||||||
|
|
||||||
|
#define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f'))
|
||||||
|
|
||||||
|
if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
|
||||||
|
//strip ':'
|
||||||
|
if(strlen(t) == 9 && t[6] == ':') t = string() << substr(t, 0, 6) << substr(t, 7);
|
||||||
|
//validate input
|
||||||
|
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
|
||||||
|
|
||||||
|
type = ProActionReplay;
|
||||||
|
unsigned r = strhex((const char*)t);
|
||||||
|
addr = r >> 8;
|
||||||
|
data = r & 0xff;
|
||||||
|
return true;
|
||||||
|
} else if(strlen(t) == 9 && t[4] == '-') {
|
||||||
|
//strip '-'
|
||||||
|
t = string() << substr(t, 0, 4) << substr(t, 5);
|
||||||
|
//validate input
|
||||||
|
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false;
|
||||||
|
|
||||||
|
type = GameGenie;
|
||||||
|
strtr(t, "df4709156bc8a23e", "0123456789abcdef");
|
||||||
|
unsigned r = strhex((const char*)t);
|
||||||
|
//8421 8421 8421 8421 8421 8421
|
||||||
|
//abcd efgh ijkl mnop qrst uvwx
|
||||||
|
//ijkl qrst opab cduv wxef ghmn
|
||||||
|
addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22)
|
||||||
|
| (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20)
|
||||||
|
| (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18)
|
||||||
|
| (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16)
|
||||||
|
| (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14)
|
||||||
|
| (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12)
|
||||||
|
| (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10)
|
||||||
|
| (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8)
|
||||||
|
| (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6)
|
||||||
|
| (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4)
|
||||||
|
| (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2)
|
||||||
|
| (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0);
|
||||||
|
data = r >> 24;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
|
||||||
|
char t[16];
|
||||||
|
|
||||||
|
if(type == ProActionReplay) {
|
||||||
|
sprintf(t, "%.6x%.2x", addr, data);
|
||||||
|
s = t;
|
||||||
|
return true;
|
||||||
|
} else if(type == GameGenie) {
|
||||||
|
unsigned r = addr;
|
||||||
|
addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22)
|
||||||
|
| (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20)
|
||||||
|
| (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18)
|
||||||
|
| (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16)
|
||||||
|
| (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14)
|
||||||
|
| (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12)
|
||||||
|
| (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10)
|
||||||
|
| (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8)
|
||||||
|
| (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6)
|
||||||
|
| (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4)
|
||||||
|
| (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2)
|
||||||
|
| (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0);
|
||||||
|
sprintf(t, "%.2x%.2x-%.4x", data, addr >> 16, addr & 0xffff);
|
||||||
|
strtr(t, "0123456789abcdef", "df4709156bc8a23e");
|
||||||
|
s = t;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//speed up S-CPU memory reads by disabling cheat code lookup when either:
|
||||||
|
//a) cheat system is disabled by user, or b) no enabled cheat codes exist
|
||||||
|
void Cheat::update_cheat_status() {
|
||||||
|
for(unsigned i = 0; i < code.size(); i++) {
|
||||||
|
if(code[i].enabled) {
|
||||||
|
cheat_enabled_code_exists = true;
|
||||||
|
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cheat_enabled_code_exists = false;
|
||||||
|
cheat_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//address lookup table manipulation and mirroring
|
||||||
|
//mirror_address() 0x000000 -> 0x7e0000
|
||||||
|
//set() enable specified address, mirror accordingly
|
||||||
|
//clear() disable specified address, mirror accordingly
|
||||||
|
unsigned Cheat::mirror_address(unsigned addr) const {
|
||||||
|
if((addr & 0x40e000) != 0x0000) return addr;
|
||||||
|
//8k WRAM mirror
|
||||||
|
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
|
||||||
|
return (0x7e0000 + (addr & 0x1fff));
|
||||||
|
}
|
||||||
|
|
||||||
|
//updates mask[] table enabled bits;
|
||||||
|
//must be called after modifying item.enabled state.
|
||||||
|
void Cheat::update(const cheat_t &item) {
|
||||||
|
for(unsigned n = 0; n < item.count; n++) {
|
||||||
|
(item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::set(unsigned addr) {
|
||||||
|
addr = mirror_address(addr);
|
||||||
|
|
||||||
|
mask[addr >> 3] |= 1 << (addr & 7);
|
||||||
|
if((addr & 0xffe000) == 0x7e0000) {
|
||||||
|
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
|
||||||
|
unsigned mirror;
|
||||||
|
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||||
|
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||||
|
mask[mirror >> 3] |= 1 << (mirror & 7);
|
||||||
|
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||||
|
mask[mirror >> 3] |= 1 << (mirror & 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::clear(unsigned addr) {
|
||||||
|
addr = mirror_address(addr);
|
||||||
|
|
||||||
|
//if there is more than one cheat code using the same address,
|
||||||
|
//(eg with a different override value) then do not clear code
|
||||||
|
//lookup table entry.
|
||||||
|
uint8_t r;
|
||||||
|
if(read(addr, r) == true) return;
|
||||||
|
|
||||||
|
mask[addr >> 3] &= ~(1 << (addr & 7));
|
||||||
|
if((addr & 0xffe000) == 0x7e0000) {
|
||||||
|
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
|
||||||
|
unsigned mirror;
|
||||||
|
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||||
|
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||||
|
mask[mirror >> 3] &= ~(1 << (mirror & 7));
|
||||||
|
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||||
|
mask[mirror >> 3] &= ~(1 << (mirror & 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//these two functions are used to safely store description text inside .cfg file format.
|
||||||
|
|
||||||
|
string& Cheat::encode_description(string &desc) const {
|
||||||
|
desc.replace("\"", "\\q");
|
||||||
|
desc.replace("\n", "\\n");
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
string& Cheat::decode_description(string &desc) const {
|
||||||
|
desc.replace("\\q", "\"");
|
||||||
|
desc.replace("\\n", "\n");
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
69
bsnes/cheat/cheat.hpp
Executable file
69
bsnes/cheat/cheat.hpp
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
class Cheat {
|
||||||
|
public:
|
||||||
|
enum type_t {
|
||||||
|
ProActionReplay,
|
||||||
|
GameGenie,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cheat_t {
|
||||||
|
bool enabled;
|
||||||
|
string code;
|
||||||
|
string desc;
|
||||||
|
|
||||||
|
unsigned count;
|
||||||
|
array<unsigned> addr;
|
||||||
|
array<uint8_t> data;
|
||||||
|
|
||||||
|
cheat_t& operator=(const cheat_t&);
|
||||||
|
bool operator<(const cheat_t&);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool decode(const char *s, cheat_t &item) const;
|
||||||
|
bool read(unsigned addr, uint8_t &data) const;
|
||||||
|
|
||||||
|
bool enabled() const;
|
||||||
|
void enable();
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
inline unsigned count() const { return code.size(); }
|
||||||
|
inline bool active() const { return cheat_enabled; }
|
||||||
|
inline bool exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); }
|
||||||
|
|
||||||
|
bool add(bool enable, const char *code, const char *desc);
|
||||||
|
bool edit(unsigned i, bool enable, const char *code, const char *desc);
|
||||||
|
bool remove(unsigned i);
|
||||||
|
bool get(unsigned i, cheat_t &item) const;
|
||||||
|
|
||||||
|
bool enabled(unsigned i) const;
|
||||||
|
void enable(unsigned i);
|
||||||
|
void disable(unsigned i);
|
||||||
|
|
||||||
|
bool load(const char *fn);
|
||||||
|
bool save(const char *fn) const;
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
Cheat();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool cheat_enabled; //cheat_enabled == (cheat_enabled_code_exists && cheat_system_enabled);
|
||||||
|
bool cheat_enabled_code_exists;
|
||||||
|
bool cheat_system_enabled;
|
||||||
|
|
||||||
|
uint8_t mask[0x200000];
|
||||||
|
vector<cheat_t> code;
|
||||||
|
|
||||||
|
bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const;
|
||||||
|
bool encode(string &str, unsigned addr, uint8_t data, type_t type) const;
|
||||||
|
|
||||||
|
void update_cheat_status();
|
||||||
|
unsigned mirror_address(unsigned addr) const;
|
||||||
|
|
||||||
|
void update(const cheat_t& item);
|
||||||
|
void set(unsigned addr);
|
||||||
|
void clear(unsigned addr);
|
||||||
|
|
||||||
|
string& encode_description(string &desc) const;
|
||||||
|
string& decode_description(string &desc) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Cheat cheat;
|
||||||
8
bsnes/chip/bsx/bsx.cpp
Executable file
8
bsnes/chip/bsx/bsx.cpp
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#define BSX_CPP
|
||||||
|
|
||||||
|
#include "bsx.hpp"
|
||||||
|
#include "bsx_base.cpp"
|
||||||
|
#include "bsx_cart.cpp"
|
||||||
|
#include "bsx_flash.cpp"
|
||||||
77
bsnes/chip/bsx/bsx.hpp
Executable file
77
bsnes/chip/bsx/bsx.hpp
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
class BSXBase : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
uint8 r2188, r2189, r218a, r218b;
|
||||||
|
uint8 r218c, r218d, r218e, r218f;
|
||||||
|
uint8 r2190, r2191, r2192, r2193;
|
||||||
|
uint8 r2194, r2195, r2196, r2197;
|
||||||
|
uint8 r2198, r2199, r219a, r219b;
|
||||||
|
uint8 r219c, r219d, r219e, r219f;
|
||||||
|
|
||||||
|
uint8 r2192_counter;
|
||||||
|
uint8 r2192_hour, r2192_minute, r2192_second;
|
||||||
|
} regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BSXCart : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
MappedRAM sram;
|
||||||
|
MappedRAM psram;
|
||||||
|
|
||||||
|
BSXCart();
|
||||||
|
~BSXCart();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 *sram_data; //256kbit SRAM
|
||||||
|
uint8 *psram_data; // 4mbit PSRAM
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8 r[16];
|
||||||
|
} regs;
|
||||||
|
|
||||||
|
void update_memory_map();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BSXFlash : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
unsigned command;
|
||||||
|
uint8 write_old;
|
||||||
|
uint8 write_new;
|
||||||
|
|
||||||
|
bool flash_enable;
|
||||||
|
bool read_enable;
|
||||||
|
bool write_enable;
|
||||||
|
} regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern BSXBase bsxbase;
|
||||||
|
extern BSXCart bsxcart;
|
||||||
|
extern BSXFlash bsxflash;
|
||||||
137
bsnes/chip/bsx/bsx_base.cpp
Executable file
137
bsnes/chip/bsx/bsx_base.cpp
Executable file
@ -0,0 +1,137 @@
|
|||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
void BSXBase::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::enable() {
|
||||||
|
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::reset() {
|
||||||
|
memset(®s, 0x00, sizeof regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXBase::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2188: return regs.r2188;
|
||||||
|
case 0x2189: return regs.r2189;
|
||||||
|
case 0x218a: return regs.r218a;
|
||||||
|
case 0x218c: return regs.r218c;
|
||||||
|
case 0x218e: return regs.r218e;
|
||||||
|
case 0x218f: return regs.r218f;
|
||||||
|
case 0x2190: return regs.r2190;
|
||||||
|
|
||||||
|
case 0x2192: {
|
||||||
|
unsigned counter = regs.r2192_counter++;
|
||||||
|
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
|
||||||
|
|
||||||
|
if(counter == 0) {
|
||||||
|
time_t rawtime;
|
||||||
|
time(&rawtime);
|
||||||
|
tm *t = localtime(&rawtime);
|
||||||
|
|
||||||
|
regs.r2192_hour = t->tm_hour;
|
||||||
|
regs.r2192_minute = t->tm_min;
|
||||||
|
regs.r2192_second = t->tm_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(counter) {
|
||||||
|
case 0: return 0x00; //???
|
||||||
|
case 1: return 0x00; //???
|
||||||
|
case 2: return 0x00; //???
|
||||||
|
case 3: return 0x00; //???
|
||||||
|
case 4: return 0x00; //???
|
||||||
|
case 5: return 0x01;
|
||||||
|
case 6: return 0x01;
|
||||||
|
case 7: return 0x00;
|
||||||
|
case 8: return 0x00;
|
||||||
|
case 9: return 0x00;
|
||||||
|
case 10: return regs.r2192_second;
|
||||||
|
case 11: return regs.r2192_minute;
|
||||||
|
case 12: return regs.r2192_hour;
|
||||||
|
case 13: return 0x00; //???
|
||||||
|
case 14: return 0x00; //???
|
||||||
|
case 15: return 0x00; //???
|
||||||
|
case 16: return 0x00; //???
|
||||||
|
case 17: return 0x00; //???
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2193: return regs.r2193 & ~0x0c;
|
||||||
|
case 0x2194: return regs.r2194;
|
||||||
|
case 0x2196: return regs.r2196;
|
||||||
|
case 0x2197: return regs.r2197;
|
||||||
|
case 0x2199: return regs.r2199;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2188: {
|
||||||
|
regs.r2188 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2189: {
|
||||||
|
regs.r2189 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218a: {
|
||||||
|
regs.r218a = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218b: {
|
||||||
|
regs.r218b = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218c: {
|
||||||
|
regs.r218c = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218e: {
|
||||||
|
regs.r218e = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218f: {
|
||||||
|
regs.r218e >>= 1;
|
||||||
|
regs.r218e = regs.r218f - regs.r218e;
|
||||||
|
regs.r218f >>= 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2191: {
|
||||||
|
regs.r2191 = data;
|
||||||
|
regs.r2192_counter = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2192: {
|
||||||
|
regs.r2190 = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2193: {
|
||||||
|
regs.r2193 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2194: {
|
||||||
|
regs.r2194 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2197: {
|
||||||
|
regs.r2197 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2199: {
|
||||||
|
regs.r2199 = data;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
101
bsnes/chip/bsx/bsx_cart.cpp
Executable file
101
bsnes/chip/bsx/bsx_cart.cpp
Executable file
@ -0,0 +1,101 @@
|
|||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
void BSXCart::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::enable() {
|
||||||
|
for(uint16 i = 0x5000; i <= 0x5fff; i++) memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::reset() {
|
||||||
|
for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00;
|
||||||
|
regs.r[0x07] = 0x80;
|
||||||
|
regs.r[0x08] = 0x80;
|
||||||
|
|
||||||
|
update_memory_map();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::update_memory_map() {
|
||||||
|
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
|
||||||
|
|
||||||
|
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||||
|
//LoROM mapping
|
||||||
|
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapLinear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||||
|
} else {
|
||||||
|
//HiROM mapping
|
||||||
|
bus.map(Bus::MapShadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapLinear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapShadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapLinear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x03] & 0x80) {
|
||||||
|
bus.map(Bus::MapLinear, 0x60, 0x6f, 0x0000, 0xffff, psram);
|
||||||
|
//bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.r[0x05] & 0x80) == 0x00) {
|
||||||
|
bus.map(Bus::MapLinear, 0x40, 0x4f, 0x0000, 0xffff, psram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.r[0x06] & 0x80) == 0x00) {
|
||||||
|
bus.map(Bus::MapLinear, 0x50, 0x5f, 0x0000, 0xffff, psram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x07] & 0x80) {
|
||||||
|
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x08] & 0x80) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXCart::mmio_read(unsigned addr) {
|
||||||
|
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||||
|
uint8 n = (addr >> 16) & 15;
|
||||||
|
return regs.r[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||||
|
return sram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||||
|
uint8 n = (addr >> 16) & 15;
|
||||||
|
regs.r[n] = data;
|
||||||
|
if(n == 0x0e && data & 0x80) update_memory_map();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||||
|
return sram.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
|
||||||
113
bsnes/chip/bsx/bsx_flash.cpp
Executable file
113
bsnes/chip/bsx/bsx_flash.cpp
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
void BSXFlash::init() {}
|
||||||
|
void BSXFlash::enable() {}
|
||||||
|
|
||||||
|
void BSXFlash::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXFlash::reset() {
|
||||||
|
regs.command = 0;
|
||||||
|
regs.write_old = 0x00;
|
||||||
|
regs.write_new = 0x00;
|
||||||
|
|
||||||
|
regs.flash_enable = false;
|
||||||
|
regs.read_enable = false;
|
||||||
|
regs.write_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BSXFlash::size() const {
|
||||||
|
return memory::bscram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXFlash::read(unsigned addr) {
|
||||||
|
if(addr == 0x0002) {
|
||||||
|
if(regs.flash_enable) return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x5555) {
|
||||||
|
if(regs.flash_enable) return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
|
||||||
|
//read flash cartridge vendor information
|
||||||
|
switch(addr - 0xff00) {
|
||||||
|
case 0x00: return 0x4d;
|
||||||
|
case 0x01: return 0x00;
|
||||||
|
case 0x02: return 0x50;
|
||||||
|
case 0x03: return 0x00;
|
||||||
|
case 0x04: return 0x00;
|
||||||
|
case 0x05: return 0x00;
|
||||||
|
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
|
||||||
|
case 0x07: return 0x00;
|
||||||
|
default: return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory::bscram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXFlash::write(unsigned addr, uint8 data) {
|
||||||
|
//there exist both read-only and read-write BS-X flash cartridges ...
|
||||||
|
//unfortunately, the vendor info is not stored inside memory dumps
|
||||||
|
//of BS-X flashcarts, so it is impossible to determine whether a
|
||||||
|
//given flashcart is writeable.
|
||||||
|
//however, it has been observed that LoROM-mapped BS-X carts always
|
||||||
|
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||||
|
//read-only flashcarts.
|
||||||
|
//below is an unfortunately necessary workaround to this problem.
|
||||||
|
if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
||||||
|
|
||||||
|
if((addr & 0xff0000) == 0) {
|
||||||
|
regs.write_old = regs.write_new;
|
||||||
|
regs.write_new = data;
|
||||||
|
|
||||||
|
if(regs.write_enable && regs.write_old == regs.write_new) {
|
||||||
|
return memory::bscram.write(addr, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(regs.write_enable) {
|
||||||
|
return memory::bscram.write(addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x0000) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
|
||||||
|
if((regs.command & 0xffff) == 0x38d0) {
|
||||||
|
regs.flash_enable = true;
|
||||||
|
regs.read_enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2aaa) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x5555) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa5570) {
|
||||||
|
regs.write_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa55a0) {
|
||||||
|
regs.write_old = 0x00;
|
||||||
|
regs.write_new = 0x00;
|
||||||
|
regs.flash_enable = true;
|
||||||
|
regs.write_enable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa55f0) {
|
||||||
|
regs.flash_enable = false;
|
||||||
|
regs.read_enable = false;
|
||||||
|
regs.write_enable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
11
bsnes/chip/chip.hpp
Executable file
11
bsnes/chip/chip.hpp
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#include "bsx/bsx.hpp"
|
||||||
|
#include "srtc/srtc.hpp"
|
||||||
|
#include "sdd1/sdd1.hpp"
|
||||||
|
#include "spc7110/spc7110.hpp"
|
||||||
|
#include "cx4/cx4.hpp"
|
||||||
|
#include "dsp1/dsp1.hpp"
|
||||||
|
#include "dsp2/dsp2.hpp"
|
||||||
|
#include "dsp3/dsp3.hpp"
|
||||||
|
#include "dsp4/dsp4.hpp"
|
||||||
|
#include "obc1/obc1.hpp"
|
||||||
|
#include "st010/st010.hpp"
|
||||||
197
bsnes/chip/cx4/cx4.cpp
Executable file
197
bsnes/chip/cx4/cx4.cpp
Executable file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
C4 emulation
|
||||||
|
|
||||||
|
Used in Rockman X2/X3 (Megaman X2/X3)
|
||||||
|
Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <../base.hpp>
|
||||||
|
#define CX4_CPP
|
||||||
|
|
||||||
|
#include "cx4.hpp"
|
||||||
|
#include "cx4data.cpp"
|
||||||
|
#include "cx4fn.cpp"
|
||||||
|
#include "cx4oam.cpp"
|
||||||
|
#include "cx4ops.cpp"
|
||||||
|
|
||||||
|
void Cx4::init() {}
|
||||||
|
void Cx4::enable() {}
|
||||||
|
|
||||||
|
uint32 Cx4::ldr(uint8 r) {
|
||||||
|
uint16 addr = 0x0080 + (r * 3);
|
||||||
|
return (reg[addr]) | (reg[addr + 1] << 8) | (reg[addr + 2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::str(uint8 r, uint32 data) {
|
||||||
|
uint16 addr = 0x0080 + (r * 3);
|
||||||
|
reg[addr ] = (data);
|
||||||
|
reg[addr + 1] = (data >> 8);
|
||||||
|
reg[addr + 2] = (data >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
|
||||||
|
int64 rx = x & 0xffffff;
|
||||||
|
int64 ry = y & 0xffffff;
|
||||||
|
if(rx & 0x800000)rx |= ~0x7fffff;
|
||||||
|
if(ry & 0x800000)ry |= ~0x7fffff;
|
||||||
|
|
||||||
|
rx *= ry;
|
||||||
|
|
||||||
|
rl = (rx) & 0xffffff;
|
||||||
|
rh = (rx >> 24) & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::sin(uint32 rx) {
|
||||||
|
r0 = rx & 0x1ff;
|
||||||
|
if(r0 & 0x100)r0 ^= 0x1ff;
|
||||||
|
if(r0 & 0x080)r0 ^= 0x0ff;
|
||||||
|
if(rx & 0x100) {
|
||||||
|
return sin_table[r0 + 0x80];
|
||||||
|
} else {
|
||||||
|
return sin_table[r0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::cos(uint32 rx) {
|
||||||
|
return sin(rx + 0x080);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::immediate_reg(uint32 start) {
|
||||||
|
r0 = ldr(0);
|
||||||
|
for(uint32 i = start; i < 48; i++) {
|
||||||
|
if((r0 & 0x0fff) < 0x0c00) {
|
||||||
|
ram[r0 & 0x0fff] = immediate_data[i];
|
||||||
|
}
|
||||||
|
r0++;
|
||||||
|
}
|
||||||
|
str(0, r0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::transfer_data() {
|
||||||
|
uint32 src;
|
||||||
|
uint16 dest, count;
|
||||||
|
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
|
||||||
|
count = (reg[0x43]) | (reg[0x44] << 8);
|
||||||
|
dest = (reg[0x45]) | (reg[0x46] << 8);
|
||||||
|
|
||||||
|
for(uint32 i=0;i<count;i++) {
|
||||||
|
write(dest++, bus.read(src++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
|
||||||
|
if(addr < 0x0c00) {
|
||||||
|
//ram
|
||||||
|
ram[addr] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x1f00) {
|
||||||
|
//unmapped
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//command register
|
||||||
|
reg[addr & 0xff] = data;
|
||||||
|
|
||||||
|
if(addr == 0x1f47) {
|
||||||
|
//memory transfer
|
||||||
|
transfer_data();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x1f4f) {
|
||||||
|
//c4 command
|
||||||
|
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
|
||||||
|
//c4 test command
|
||||||
|
reg[0x80] = data >> 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(data) {
|
||||||
|
case 0x00: op00(); break;
|
||||||
|
case 0x01: op01(); break;
|
||||||
|
case 0x05: op05(); break;
|
||||||
|
case 0x0d: op0d(); break;
|
||||||
|
case 0x10: op10(); break;
|
||||||
|
case 0x13: op13(); break;
|
||||||
|
case 0x15: op15(); break;
|
||||||
|
case 0x1f: op1f(); break;
|
||||||
|
case 0x22: op22(); break;
|
||||||
|
case 0x25: op25(); break;
|
||||||
|
case 0x2d: op2d(); break;
|
||||||
|
case 0x40: op40(); break;
|
||||||
|
case 0x54: op54(); break;
|
||||||
|
case 0x5c: op5c(); break;
|
||||||
|
case 0x5e: op5e(); break;
|
||||||
|
case 0x60: op60(); break;
|
||||||
|
case 0x62: op62(); break;
|
||||||
|
case 0x64: op64(); break;
|
||||||
|
case 0x66: op66(); break;
|
||||||
|
case 0x68: op68(); break;
|
||||||
|
case 0x6a: op6a(); break;
|
||||||
|
case 0x6c: op6c(); break;
|
||||||
|
case 0x6e: op6e(); break;
|
||||||
|
case 0x70: op70(); break;
|
||||||
|
case 0x72: op72(); break;
|
||||||
|
case 0x74: op74(); break;
|
||||||
|
case 0x76: op76(); break;
|
||||||
|
case 0x78: op78(); break;
|
||||||
|
case 0x7a: op7a(); break;
|
||||||
|
case 0x7c: op7c(); break;
|
||||||
|
case 0x89: op89(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writeb(uint16 addr, uint8 data) {
|
||||||
|
write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writew(uint16 addr, uint16 data) {
|
||||||
|
write(addr, data);
|
||||||
|
write(addr + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writel(uint16 addr, uint32 data) {
|
||||||
|
write(addr, data);
|
||||||
|
write(addr + 1, data >> 8);
|
||||||
|
write(addr + 2, data >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Cx4::read(unsigned addr) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
|
||||||
|
if(addr < 0x0c00) {
|
||||||
|
return ram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x1f00) {
|
||||||
|
return reg[addr & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Cx4::readb(uint16 addr) {
|
||||||
|
return read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Cx4::readw(uint16 addr) {
|
||||||
|
return read(addr) | (read(addr + 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::readl(uint16 addr) {
|
||||||
|
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::reset() {
|
||||||
|
memset(ram, 0, 0x0c00);
|
||||||
|
memset(reg, 0, 0x0100);
|
||||||
|
}
|
||||||
97
bsnes/chip/cx4/cx4.hpp
Executable file
97
bsnes/chip/cx4/cx4.hpp
Executable file
@ -0,0 +1,97 @@
|
|||||||
|
class Cx4 : public Memory {
|
||||||
|
private:
|
||||||
|
uint8 ram[0x0c00];
|
||||||
|
uint8 reg[0x0100];
|
||||||
|
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
|
||||||
|
r8, r9, r10, r11, r12, r13, r14, r15;
|
||||||
|
|
||||||
|
static const uint8 immediate_data[48];
|
||||||
|
static const uint16 wave_data[40];
|
||||||
|
static const uint32 sin_table[256];
|
||||||
|
|
||||||
|
static const int16 SinTable[512];
|
||||||
|
static const int16 CosTable[512];
|
||||||
|
|
||||||
|
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
|
||||||
|
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
|
||||||
|
|
||||||
|
double tanval;
|
||||||
|
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
|
||||||
|
|
||||||
|
void C4TransfWireFrame();
|
||||||
|
void C4TransfWireFrame2();
|
||||||
|
void C4CalcWireFrame();
|
||||||
|
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
|
||||||
|
void C4DrawWireFrame();
|
||||||
|
void C4DoScaleRotate(int row_padding);
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32 ldr(uint8 r);
|
||||||
|
void str(uint8 r, uint32 data);
|
||||||
|
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
|
||||||
|
uint32 sin(uint32 rx);
|
||||||
|
uint32 cos(uint32 rx);
|
||||||
|
|
||||||
|
void transfer_data();
|
||||||
|
void immediate_reg(uint32 num);
|
||||||
|
|
||||||
|
void op00_00();
|
||||||
|
void op00_03();
|
||||||
|
void op00_05();
|
||||||
|
void op00_07();
|
||||||
|
void op00_08();
|
||||||
|
void op00_0b();
|
||||||
|
void op00_0c();
|
||||||
|
|
||||||
|
void op00();
|
||||||
|
void op01();
|
||||||
|
void op05();
|
||||||
|
void op0d();
|
||||||
|
void op10();
|
||||||
|
void op13();
|
||||||
|
void op15();
|
||||||
|
void op1f();
|
||||||
|
void op22();
|
||||||
|
void op25();
|
||||||
|
void op2d();
|
||||||
|
void op40();
|
||||||
|
void op54();
|
||||||
|
void op5c();
|
||||||
|
void op5e();
|
||||||
|
void op60();
|
||||||
|
void op62();
|
||||||
|
void op64();
|
||||||
|
void op66();
|
||||||
|
void op68();
|
||||||
|
void op6a();
|
||||||
|
void op6c();
|
||||||
|
void op6e();
|
||||||
|
void op70();
|
||||||
|
void op72();
|
||||||
|
void op74();
|
||||||
|
void op76();
|
||||||
|
void op78();
|
||||||
|
void op7a();
|
||||||
|
void op7c();
|
||||||
|
void op89();
|
||||||
|
|
||||||
|
uint8 readb(uint16 addr);
|
||||||
|
uint16 readw(uint16 addr);
|
||||||
|
uint32 readl(uint16 addr);
|
||||||
|
|
||||||
|
void writeb(uint16 addr, uint8 data);
|
||||||
|
void writew(uint16 addr, uint16 data);
|
||||||
|
void writel(uint16 addr, uint32 data);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Cx4 cx4;
|
||||||
187
bsnes/chip/cx4/cx4data.cpp
Executable file
187
bsnes/chip/cx4/cx4data.cpp
Executable file
@ -0,0 +1,187 @@
|
|||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
const uint8 Cx4::immediate_data[48] = {
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
|
||||||
|
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16 Cx4::wave_data[40] = {
|
||||||
|
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
|
||||||
|
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
|
||||||
|
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
|
||||||
|
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
|
||||||
|
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32 Cx4::sin_table[256] = {
|
||||||
|
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
|
||||||
|
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
|
||||||
|
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
|
||||||
|
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
|
||||||
|
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
|
||||||
|
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
|
||||||
|
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
|
||||||
|
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
|
||||||
|
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
|
||||||
|
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
|
||||||
|
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
|
||||||
|
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
|
||||||
|
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
|
||||||
|
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
|
||||||
|
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
|
||||||
|
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
|
||||||
|
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
|
||||||
|
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
|
||||||
|
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
|
||||||
|
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
|
||||||
|
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
|
||||||
|
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
|
||||||
|
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
|
||||||
|
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
|
||||||
|
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
|
||||||
|
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
|
||||||
|
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
|
||||||
|
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
|
||||||
|
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
|
||||||
|
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
|
||||||
|
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
|
||||||
|
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 Cx4::SinTable[512] = {
|
||||||
|
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||||
|
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||||
|
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||||
|
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||||
|
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||||
|
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||||
|
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||||
|
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||||
|
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||||
|
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||||
|
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||||
|
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||||
|
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||||
|
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||||
|
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||||
|
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
|
||||||
|
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||||
|
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||||
|
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||||
|
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||||
|
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||||
|
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||||
|
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||||
|
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||||
|
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||||
|
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||||
|
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||||
|
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||||
|
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||||
|
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||||
|
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||||
|
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||||
|
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||||
|
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||||
|
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||||
|
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||||
|
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||||
|
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||||
|
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||||
|
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||||
|
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||||
|
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||||
|
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||||
|
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||||
|
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||||
|
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||||
|
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||||
|
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||||
|
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||||
|
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||||
|
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||||
|
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||||
|
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||||
|
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||||
|
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||||
|
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||||
|
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||||
|
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||||
|
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||||
|
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||||
|
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||||
|
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||||
|
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||||
|
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 Cx4::CosTable[512] = {
|
||||||
|
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||||
|
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||||
|
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||||
|
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||||
|
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||||
|
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||||
|
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||||
|
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||||
|
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||||
|
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||||
|
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||||
|
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||||
|
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||||
|
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||||
|
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||||
|
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||||
|
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||||
|
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||||
|
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||||
|
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||||
|
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||||
|
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||||
|
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||||
|
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||||
|
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||||
|
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||||
|
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||||
|
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||||
|
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||||
|
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||||
|
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||||
|
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||||
|
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||||
|
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||||
|
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||||
|
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||||
|
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||||
|
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||||
|
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||||
|
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||||
|
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||||
|
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||||
|
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||||
|
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||||
|
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||||
|
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||||
|
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||||
|
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
|
||||||
|
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||||
|
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||||
|
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||||
|
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||||
|
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||||
|
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||||
|
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||||
|
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||||
|
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||||
|
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||||
|
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||||
|
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||||
|
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||||
|
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||||
|
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||||
|
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
246
bsnes/chip/cx4/cx4fn.cpp
Executable file
246
bsnes/chip/cx4/cx4fn.cpp
Executable file
@ -0,0 +1,246 @@
|
|||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
|
||||||
|
#define sar(b, n) ((b) >> (n))
|
||||||
|
#ifdef PI
|
||||||
|
#undef PI
|
||||||
|
#endif
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
|
||||||
|
//Wireframe Helpers
|
||||||
|
void Cx4::C4TransfWireFrame() {
|
||||||
|
c4x = (double)C4WFXVal;
|
||||||
|
c4y = (double)C4WFYVal;
|
||||||
|
c4z = (double)C4WFZVal - 0x95;
|
||||||
|
|
||||||
|
//Rotate X
|
||||||
|
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||||
|
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||||
|
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||||
|
|
||||||
|
//Rotate Y
|
||||||
|
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||||
|
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||||
|
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||||
|
|
||||||
|
//Rotate Z
|
||||||
|
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||||
|
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||||
|
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||||
|
|
||||||
|
//Scale
|
||||||
|
C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||||
|
C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::C4CalcWireFrame() {
|
||||||
|
C4WFXVal = C4WFX2Val - C4WFXVal;
|
||||||
|
C4WFYVal = C4WFY2Val - C4WFYVal;
|
||||||
|
|
||||||
|
if(abs(C4WFXVal) > abs(C4WFYVal)) {
|
||||||
|
C4WFDist = abs(C4WFXVal) + 1;
|
||||||
|
C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
|
||||||
|
C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
|
||||||
|
} else if(C4WFYVal != 0) {
|
||||||
|
C4WFDist = abs(C4WFYVal) + 1;
|
||||||
|
C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
|
||||||
|
C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
|
||||||
|
} else {
|
||||||
|
C4WFDist = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::C4TransfWireFrame2() {
|
||||||
|
c4x = (double)C4WFXVal;
|
||||||
|
c4y = (double)C4WFYVal;
|
||||||
|
c4z = (double)C4WFZVal;
|
||||||
|
|
||||||
|
//Rotate X
|
||||||
|
tanval = -(double)C4WFX2Val * PI * 2 / 128;
|
||||||
|
c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
|
||||||
|
c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
|
||||||
|
|
||||||
|
//Rotate Y
|
||||||
|
tanval = -(double)C4WFY2Val * PI * 2 / 128;
|
||||||
|
c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
|
||||||
|
c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
|
||||||
|
|
||||||
|
//Rotate Z
|
||||||
|
tanval = -(double)C4WFDist * PI * 2 / 128;
|
||||||
|
c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
|
||||||
|
c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
|
||||||
|
|
||||||
|
//Scale
|
||||||
|
C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
|
||||||
|
C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::C4DrawWireFrame() {
|
||||||
|
uint32 line = readl(0x1f80);
|
||||||
|
uint32 point1, point2;
|
||||||
|
int16 X1, Y1, Z1;
|
||||||
|
int16 X2, Y2, Z2;
|
||||||
|
uint8 Color;
|
||||||
|
for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
|
||||||
|
if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
|
||||||
|
int32 tmp = line - 5;
|
||||||
|
while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
|
||||||
|
point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
|
||||||
|
} else {
|
||||||
|
point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
|
||||||
|
}
|
||||||
|
point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
|
||||||
|
|
||||||
|
X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
|
||||||
|
Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
|
||||||
|
Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
|
||||||
|
X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
|
||||||
|
Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
|
||||||
|
Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
|
||||||
|
Color = bus.read(line + 4);
|
||||||
|
C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
|
||||||
|
//Transform coordinates
|
||||||
|
C4WFXVal = (int16)X1;
|
||||||
|
C4WFYVal = (int16)Y1;
|
||||||
|
C4WFZVal = Z1;
|
||||||
|
C4WFScale = read(0x1f90);
|
||||||
|
C4WFX2Val = read(0x1f86);
|
||||||
|
C4WFY2Val = read(0x1f87);
|
||||||
|
C4WFDist = read(0x1f88);
|
||||||
|
C4TransfWireFrame2();
|
||||||
|
X1 = (C4WFXVal + 48) << 8;
|
||||||
|
Y1 = (C4WFYVal + 48) << 8;
|
||||||
|
|
||||||
|
C4WFXVal = (int16)X2;
|
||||||
|
C4WFYVal = (int16)Y2;
|
||||||
|
C4WFZVal = Z2;
|
||||||
|
C4TransfWireFrame2();
|
||||||
|
X2 = (C4WFXVal + 48) << 8;
|
||||||
|
Y2 = (C4WFYVal + 48) << 8;
|
||||||
|
|
||||||
|
//Get line info
|
||||||
|
C4WFXVal = (int16)(X1 >> 8);
|
||||||
|
C4WFYVal = (int16)(Y1 >> 8);
|
||||||
|
C4WFX2Val = (int16)(X2 >> 8);
|
||||||
|
C4WFY2Val = (int16)(Y2 >> 8);
|
||||||
|
C4CalcWireFrame();
|
||||||
|
X2 = (int16)C4WFXVal;
|
||||||
|
Y2 = (int16)C4WFYVal;
|
||||||
|
|
||||||
|
//Render line
|
||||||
|
for(int32 i = C4WFDist ? C4WFDist : 1; i > 0; i--) {
|
||||||
|
if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
|
||||||
|
uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
|
||||||
|
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
|
||||||
|
ram[addr + 0x300] &= ~bit;
|
||||||
|
ram[addr + 0x301] &= ~bit;
|
||||||
|
if(Color & 1) { ram[addr + 0x300] |= bit; }
|
||||||
|
if(Color & 2) { ram[addr + 0x301] |= bit; }
|
||||||
|
}
|
||||||
|
X1 += X2;
|
||||||
|
Y1 += Y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::C4DoScaleRotate(int row_padding) {
|
||||||
|
int16 A, B, C, D;
|
||||||
|
|
||||||
|
//Calculate matrix
|
||||||
|
int32 XScale = readw(0x1f8f);
|
||||||
|
int32 YScale = readw(0x1f92);
|
||||||
|
if(XScale & 0x8000)XScale = 0x7fff;
|
||||||
|
if(YScale & 0x8000)YScale = 0x7fff;
|
||||||
|
|
||||||
|
if(readw(0x1f80) == 0) { //no rotation
|
||||||
|
A = (int16)XScale;
|
||||||
|
B = 0;
|
||||||
|
C = 0;
|
||||||
|
D = (int16)YScale;
|
||||||
|
} else if(readw(0x1f80) == 128) { //90 degree rotation
|
||||||
|
A = 0;
|
||||||
|
B = (int16)(-YScale);
|
||||||
|
C = (int16)XScale;
|
||||||
|
D = 0;
|
||||||
|
} else if(readw(0x1f80) == 256) { //180 degree rotation
|
||||||
|
A = (int16)(-XScale);
|
||||||
|
B = 0;
|
||||||
|
C = 0;
|
||||||
|
D = (int16)(-YScale);
|
||||||
|
} else if(readw(0x1f80) == 384) { //270 degree rotation
|
||||||
|
A = 0;
|
||||||
|
B = (int16)YScale;
|
||||||
|
C = (int16)(-XScale);
|
||||||
|
D = 0;
|
||||||
|
} else {
|
||||||
|
A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||||
|
B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
|
||||||
|
C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
|
||||||
|
D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculate Pixel Resolution
|
||||||
|
uint8 w = read(0x1f89) & ~7;
|
||||||
|
uint8 h = read(0x1f8c) & ~7;
|
||||||
|
|
||||||
|
//Clear the output RAM
|
||||||
|
memset(ram, 0, (w + row_padding / 4) * h / 2);
|
||||||
|
|
||||||
|
int32 Cx = (int16)readw(0x1f83);
|
||||||
|
int32 Cy = (int16)readw(0x1f86);
|
||||||
|
|
||||||
|
//Calculate start position (i.e. (Ox, Oy) = (0, 0))
|
||||||
|
//The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
|
||||||
|
//the function. We do Cx*A etc normally because the matrix parameters
|
||||||
|
//already have the fractional parts.
|
||||||
|
int32 LineX = (Cx << 12) - Cx * A - Cx * B;
|
||||||
|
int32 LineY = (Cy << 12) - Cy * C - Cy * D;
|
||||||
|
|
||||||
|
//Start loop
|
||||||
|
uint32 X, Y;
|
||||||
|
uint8 byte;
|
||||||
|
int32 outidx = 0;
|
||||||
|
uint8 bit = 0x80;
|
||||||
|
for(int32 y = 0; y < h; y++) {
|
||||||
|
X = LineX;
|
||||||
|
Y = LineY;
|
||||||
|
for(int32 x = 0; x < w; x++) {
|
||||||
|
if((X >> 12) >= w || (Y >> 12) >= h) {
|
||||||
|
byte = 0;
|
||||||
|
} else {
|
||||||
|
uint32 addr = (Y >> 12) * w + (X >> 12);
|
||||||
|
byte = read(0x600 + (addr >> 1));
|
||||||
|
if(addr & 1) { byte >>= 4; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//De-bitplanify
|
||||||
|
if(byte & 1) { ram[outidx ] |= bit; }
|
||||||
|
if(byte & 2) { ram[outidx + 1] |= bit; }
|
||||||
|
if(byte & 4) { ram[outidx + 16] |= bit; }
|
||||||
|
if(byte & 8) { ram[outidx + 17] |= bit; }
|
||||||
|
|
||||||
|
bit >>= 1;
|
||||||
|
if(!bit) {
|
||||||
|
bit = 0x80;
|
||||||
|
outidx += 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
X += A; //Add 1 to output x => add an A and a C
|
||||||
|
Y += C;
|
||||||
|
}
|
||||||
|
outidx += 2 + row_padding;
|
||||||
|
if(outidx & 0x10) {
|
||||||
|
outidx &= ~0x10;
|
||||||
|
} else {
|
||||||
|
outidx -= w * 4 + row_padding;
|
||||||
|
}
|
||||||
|
LineX += B; //Add 1 to output y => add a B and a D
|
||||||
|
LineY += D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
223
bsnes/chip/cx4/cx4oam.cpp
Executable file
223
bsnes/chip/cx4/cx4oam.cpp
Executable file
@ -0,0 +1,223 @@
|
|||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
//Build OAM
|
||||||
|
void Cx4::op00_00() {
|
||||||
|
uint32 oamptr = ram[0x626] << 2;
|
||||||
|
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
|
||||||
|
//clear oam-to-be
|
||||||
|
if(i >= 0)ram[i] = 0xe0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 globalx, globaly;
|
||||||
|
uint32 oamptr2;
|
||||||
|
int16 sprx, spry;
|
||||||
|
uint8 sprname, sprattr;
|
||||||
|
uint8 sprcount;
|
||||||
|
globalx = readw(0x621);
|
||||||
|
globaly = readw(0x623);
|
||||||
|
oamptr2 = 0x200 + (ram[0x626] >> 2);
|
||||||
|
|
||||||
|
if(!ram[0x620])return;
|
||||||
|
|
||||||
|
sprcount = 128 - ram[0x626];
|
||||||
|
uint8 offset = (ram[0x626] & 3) * 2;
|
||||||
|
uint32 srcptr = 0x220;
|
||||||
|
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
|
||||||
|
sprx = readw(srcptr) - globalx;
|
||||||
|
spry = readw(srcptr + 2) - globaly;
|
||||||
|
sprname = ram[srcptr + 5];
|
||||||
|
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
|
||||||
|
|
||||||
|
uint32 spraddr = readl(srcptr + 7);
|
||||||
|
if(bus.read(spraddr)) {
|
||||||
|
int16 x, y;
|
||||||
|
for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
|
||||||
|
x = (int8)bus.read(spraddr + 1);
|
||||||
|
if(sprattr & 0x40) {
|
||||||
|
x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
|
||||||
|
}
|
||||||
|
x += sprx;
|
||||||
|
if(x >= -16 && x <= 272) {
|
||||||
|
y = (int8)bus.read(spraddr + 2);
|
||||||
|
if(sprattr & 0x80) {
|
||||||
|
y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
|
||||||
|
}
|
||||||
|
y += spry;
|
||||||
|
if(y >= -16 && y <= 224) {
|
||||||
|
ram[oamptr ] = (uint8)x;
|
||||||
|
ram[oamptr + 1] = (uint8)y;
|
||||||
|
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
|
||||||
|
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
|
||||||
|
ram[oamptr2] &= ~(3 << offset);
|
||||||
|
if(x & 0x100)ram[oamptr2] |= 1 << offset;
|
||||||
|
if(bus.read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
|
||||||
|
oamptr += 4;
|
||||||
|
sprcount--;
|
||||||
|
offset = (offset + 2) & 6;
|
||||||
|
if(!offset)oamptr2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(sprcount > 0) {
|
||||||
|
ram[oamptr ] = (uint8)sprx;
|
||||||
|
ram[oamptr + 1] = (uint8)spry;
|
||||||
|
ram[oamptr + 2] = sprname;
|
||||||
|
ram[oamptr + 3] = sprattr;
|
||||||
|
ram[oamptr2] &= ~(3 << offset);
|
||||||
|
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
|
||||||
|
else ram[oamptr2] |= 2 << offset;
|
||||||
|
oamptr += 4;
|
||||||
|
sprcount--;
|
||||||
|
offset = (offset + 2) & 6;
|
||||||
|
if(!offset)oamptr2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Scale and Rotate
|
||||||
|
void Cx4::op00_03() {
|
||||||
|
C4DoScaleRotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Transform Lines
|
||||||
|
void Cx4::op00_05() {
|
||||||
|
C4WFX2Val = read(0x1f83);
|
||||||
|
C4WFY2Val = read(0x1f86);
|
||||||
|
C4WFDist = read(0x1f89);
|
||||||
|
C4WFScale = read(0x1f8c);
|
||||||
|
|
||||||
|
//Transform Vertices
|
||||||
|
uint32 ptr = 0;
|
||||||
|
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
|
||||||
|
C4WFXVal = readw(ptr + 1);
|
||||||
|
C4WFYVal = readw(ptr + 5);
|
||||||
|
C4WFZVal = readw(ptr + 9);
|
||||||
|
C4TransfWireFrame();
|
||||||
|
|
||||||
|
//Displace
|
||||||
|
writew(ptr + 1, C4WFXVal + 0x80);
|
||||||
|
writew(ptr + 5, C4WFYVal + 0x50);
|
||||||
|
}
|
||||||
|
|
||||||
|
writew(0x600, 23);
|
||||||
|
writew(0x602, 0x60);
|
||||||
|
writew(0x605, 0x40);
|
||||||
|
writew(0x600 + 8, 23);
|
||||||
|
writew(0x602 + 8, 0x60);
|
||||||
|
writew(0x605 + 8, 0x40);
|
||||||
|
|
||||||
|
ptr = 0xb02;
|
||||||
|
uint32 ptr2 = 0;
|
||||||
|
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
|
||||||
|
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
|
||||||
|
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
|
||||||
|
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
|
||||||
|
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
|
||||||
|
C4CalcWireFrame();
|
||||||
|
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
|
||||||
|
writew(ptr2 + 0x602, C4WFXVal);
|
||||||
|
writew(ptr2 + 0x605, C4WFYVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Scale and Rotate
|
||||||
|
void Cx4::op00_07() {
|
||||||
|
C4DoScaleRotate(64);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw Wireframe
|
||||||
|
void Cx4::op00_08() {
|
||||||
|
C4DrawWireFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Disintegrate
|
||||||
|
void Cx4::op00_0b() {
|
||||||
|
uint8 width, height;
|
||||||
|
uint32 startx, starty;
|
||||||
|
uint32 srcptr;
|
||||||
|
uint32 x, y;
|
||||||
|
int32 scalex, scaley;
|
||||||
|
int32 cx, cy;
|
||||||
|
int32 i, j;
|
||||||
|
width = read(0x1f89);
|
||||||
|
height = read(0x1f8c);
|
||||||
|
cx = readw(0x1f80);
|
||||||
|
cy = readw(0x1f83);
|
||||||
|
|
||||||
|
scalex = (int16)readw(0x1f86);
|
||||||
|
scaley = (int16)readw(0x1f8f);
|
||||||
|
startx = -cx * scalex + (cx << 8);
|
||||||
|
starty = -cy * scaley + (cy << 8);
|
||||||
|
srcptr = 0x600;
|
||||||
|
|
||||||
|
for(i = 0; i < (width * height) >> 1; i++) {
|
||||||
|
write(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = starty, i = 0;i < height; i++, y += scaley) {
|
||||||
|
for(x = startx, j = 0;j < width; j++, x += scalex) {
|
||||||
|
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
|
||||||
|
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
|
||||||
|
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
|
||||||
|
uint8 mask = 0x80 >> ((x >> 8) & 7);
|
||||||
|
if(pixel & 1)ram[index ] |= mask;
|
||||||
|
if(pixel & 2)ram[index + 1] |= mask;
|
||||||
|
if(pixel & 4)ram[index + 16] |= mask;
|
||||||
|
if(pixel & 8)ram[index + 17] |= mask;
|
||||||
|
}
|
||||||
|
if(j & 1)srcptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bitplane Wave
|
||||||
|
void Cx4::op00_0c() {
|
||||||
|
uint32 destptr = 0;
|
||||||
|
uint32 waveptr = read(0x1f83);
|
||||||
|
uint16 mask1 = 0xc0c0;
|
||||||
|
uint16 mask2 = 0x3f3f;
|
||||||
|
|
||||||
|
for(int j = 0; j < 0x10; j++) {
|
||||||
|
do {
|
||||||
|
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||||
|
for(int i = 0; i < 40; i++) {
|
||||||
|
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||||
|
if(height >= 0) {
|
||||||
|
if(height < 8) {
|
||||||
|
temp |= mask1 & readw(0xa00 + height * 2);
|
||||||
|
} else {
|
||||||
|
temp |= mask1 & 0xff00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writew(destptr + wave_data[i], temp);
|
||||||
|
height++;
|
||||||
|
}
|
||||||
|
waveptr = (waveptr + 1) & 0x7f;
|
||||||
|
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||||
|
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||||
|
} while(mask1 != 0xc0c0);
|
||||||
|
destptr += 16;
|
||||||
|
|
||||||
|
do {
|
||||||
|
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||||
|
for(int i = 0; i < 40; i++) {
|
||||||
|
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||||
|
if(height >= 0) {
|
||||||
|
if(height < 8) {
|
||||||
|
temp |= mask1 & readw(0xa10 + height * 2);
|
||||||
|
} else {
|
||||||
|
temp |= mask1 & 0xff00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writew(destptr + wave_data[i], temp);
|
||||||
|
height++;
|
||||||
|
}
|
||||||
|
waveptr = (waveptr + 1) & 0x7f;
|
||||||
|
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||||
|
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||||
|
} while(mask1 != 0xc0c0);
|
||||||
|
destptr += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
226
bsnes/chip/cx4/cx4ops.cpp
Executable file
226
bsnes/chip/cx4/cx4ops.cpp
Executable file
@ -0,0 +1,226 @@
|
|||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
//Sprite Functions
|
||||||
|
void Cx4::op00() {
|
||||||
|
switch(reg[0x4d]) {
|
||||||
|
case 0x00:op00_00();break;
|
||||||
|
case 0x03:op00_03();break;
|
||||||
|
case 0x05:op00_05();break;
|
||||||
|
case 0x07:op00_07();break;
|
||||||
|
case 0x08:op00_08();break;
|
||||||
|
case 0x0b:op00_0b();break;
|
||||||
|
case 0x0c:op00_0c();break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw Wireframe
|
||||||
|
void Cx4::op01() {
|
||||||
|
memset(ram + 0x300, 0, 2304);
|
||||||
|
C4DrawWireFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Propulsion
|
||||||
|
void Cx4::op05() {
|
||||||
|
int32 temp = 0x10000;
|
||||||
|
if(readw(0x1f83)) {
|
||||||
|
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
|
||||||
|
}
|
||||||
|
writew(0x1f80, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Vector length
|
||||||
|
void Cx4::op0d() {
|
||||||
|
C41FXVal = readw(0x1f80);
|
||||||
|
C41FYVal = readw(0x1f83);
|
||||||
|
C41FDistVal = readw(0x1f86);
|
||||||
|
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
|
||||||
|
tanval = (double)C41FDistVal / tanval;
|
||||||
|
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
|
||||||
|
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
|
||||||
|
writew(0x1f89, C41FXVal);
|
||||||
|
writew(0x1f8c, C41FYVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Triangle
|
||||||
|
void Cx4::op10() {
|
||||||
|
r0 = ldr(0);
|
||||||
|
r1 = ldr(1);
|
||||||
|
|
||||||
|
r4 = r0 & 0x1ff;
|
||||||
|
if(r1 & 0x8000)r1 |= ~0x7fff;
|
||||||
|
|
||||||
|
mul(cos(r4), r1, r5, r2);
|
||||||
|
r5 = (r5 >> 16) & 0xff;
|
||||||
|
r2 = (r2 << 8) + r5;
|
||||||
|
|
||||||
|
mul(sin(r4), r1, r5, r3);
|
||||||
|
r5 = (r5 >> 16) & 0xff;
|
||||||
|
r3 = (r3 << 8) + r5;
|
||||||
|
|
||||||
|
str(0, r0);
|
||||||
|
str(1, r1);
|
||||||
|
str(2, r2);
|
||||||
|
str(3, r3);
|
||||||
|
str(4, r4);
|
||||||
|
str(5, r5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Triangle
|
||||||
|
void Cx4::op13() {
|
||||||
|
r0 = ldr(0);
|
||||||
|
r1 = ldr(1);
|
||||||
|
|
||||||
|
r4 = r0 & 0x1ff;
|
||||||
|
|
||||||
|
mul(cos(r4), r1, r5, r2);
|
||||||
|
r5 = (r5 >> 8) & 0xffff;
|
||||||
|
r2 = (r2 << 16) + r5;
|
||||||
|
|
||||||
|
mul(sin(r4), r1, r5, r3);
|
||||||
|
r5 = (r5 >> 8) & 0xffff;
|
||||||
|
r3 = (r3 << 16) + r5;
|
||||||
|
|
||||||
|
str(0, r0);
|
||||||
|
str(1, r1);
|
||||||
|
str(2, r2);
|
||||||
|
str(3, r3);
|
||||||
|
str(4, r4);
|
||||||
|
str(5, r5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pythagorean
|
||||||
|
void Cx4::op15() {
|
||||||
|
C41FXVal = readw(0x1f80);
|
||||||
|
C41FYVal = readw(0x1f83);
|
||||||
|
C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
|
||||||
|
writew(0x1f80, C41FDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculate distance
|
||||||
|
void Cx4::op1f() {
|
||||||
|
C41FXVal = readw(0x1f80);
|
||||||
|
C41FYVal = readw(0x1f83);
|
||||||
|
if(!C41FXVal) {
|
||||||
|
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
|
||||||
|
} else {
|
||||||
|
tanval = ((double)C41FYVal) / ((double)C41FXVal);
|
||||||
|
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
|
||||||
|
C41FAngleRes = C41FAngleRes;
|
||||||
|
if(C41FXVal < 0) {
|
||||||
|
C41FAngleRes += 0x100;
|
||||||
|
}
|
||||||
|
C41FAngleRes &= 0x1ff;
|
||||||
|
}
|
||||||
|
writew(0x1f86, C41FAngleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Trapezoid
|
||||||
|
void Cx4::op22() {
|
||||||
|
int16 angle1 = readw(0x1f8c) & 0x1ff;
|
||||||
|
int16 angle2 = readw(0x1f8f) & 0x1ff;
|
||||||
|
int32 tan1 = Tan(angle1);
|
||||||
|
int32 tan2 = Tan(angle2);
|
||||||
|
int16 y = readw(0x1f83) - readw(0x1f89);
|
||||||
|
int16 left, right;
|
||||||
|
for(int32 j = 0; j < 225; j++, y++) {
|
||||||
|
if(y >= 0) {
|
||||||
|
left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
|
||||||
|
right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
|
||||||
|
|
||||||
|
if(left < 0 && right < 0) {
|
||||||
|
left = 1;
|
||||||
|
right = 0;
|
||||||
|
} else if(left < 0) {
|
||||||
|
left = 0;
|
||||||
|
} else if(right < 0) {
|
||||||
|
right = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(left > 255 && right > 255) {
|
||||||
|
left = 255;
|
||||||
|
right = 254;
|
||||||
|
} else if(left > 255) {
|
||||||
|
left = 255;
|
||||||
|
} else if(right > 255) {
|
||||||
|
right = 255;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left = 1;
|
||||||
|
right = 0;
|
||||||
|
}
|
||||||
|
ram[j + 0x800] = (uint8)left;
|
||||||
|
ram[j + 0x900] = (uint8)right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Multiply
|
||||||
|
void Cx4::op25() {
|
||||||
|
r0 = ldr(0);
|
||||||
|
r1 = ldr(1);
|
||||||
|
mul(r0, r1, r0, r1);
|
||||||
|
str(0, r0);
|
||||||
|
str(1, r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Transform Coords
|
||||||
|
void Cx4::op2d() {
|
||||||
|
C4WFXVal = readw(0x1f81);
|
||||||
|
C4WFYVal = readw(0x1f84);
|
||||||
|
C4WFZVal = readw(0x1f87);
|
||||||
|
C4WFX2Val = read (0x1f89);
|
||||||
|
C4WFY2Val = read (0x1f8a);
|
||||||
|
C4WFDist = read (0x1f8b);
|
||||||
|
C4WFScale = readw(0x1f90);
|
||||||
|
C4TransfWireFrame2();
|
||||||
|
writew(0x1f80, C4WFXVal);
|
||||||
|
writew(0x1f83, C4WFYVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sum
|
||||||
|
void Cx4::op40() {
|
||||||
|
r0 = 0;
|
||||||
|
for(uint32 i=0;i<0x800;i++) {
|
||||||
|
r0 += ram[i];
|
||||||
|
}
|
||||||
|
str(0, r0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Square
|
||||||
|
void Cx4::op54() {
|
||||||
|
r0 = ldr(0);
|
||||||
|
mul(r0, r0, r1, r2);
|
||||||
|
str(1, r1);
|
||||||
|
str(2, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Immediate Register
|
||||||
|
void Cx4::op5c() {
|
||||||
|
str(0, 0x000000);
|
||||||
|
immediate_reg(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Immediate Register (Multiple)
|
||||||
|
void Cx4::op5e() { immediate_reg( 0); }
|
||||||
|
void Cx4::op60() { immediate_reg( 3); }
|
||||||
|
void Cx4::op62() { immediate_reg( 6); }
|
||||||
|
void Cx4::op64() { immediate_reg( 9); }
|
||||||
|
void Cx4::op66() { immediate_reg(12); }
|
||||||
|
void Cx4::op68() { immediate_reg(15); }
|
||||||
|
void Cx4::op6a() { immediate_reg(18); }
|
||||||
|
void Cx4::op6c() { immediate_reg(21); }
|
||||||
|
void Cx4::op6e() { immediate_reg(24); }
|
||||||
|
void Cx4::op70() { immediate_reg(27); }
|
||||||
|
void Cx4::op72() { immediate_reg(30); }
|
||||||
|
void Cx4::op74() { immediate_reg(33); }
|
||||||
|
void Cx4::op76() { immediate_reg(36); }
|
||||||
|
void Cx4::op78() { immediate_reg(39); }
|
||||||
|
void Cx4::op7a() { immediate_reg(42); }
|
||||||
|
void Cx4::op7c() { immediate_reg(45); }
|
||||||
|
|
||||||
|
//Immediate ROM
|
||||||
|
void Cx4::op89() {
|
||||||
|
str(0, 0x054336);
|
||||||
|
str(1, 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
59
bsnes/chip/dsp1/dsp1.cpp
Executable file
59
bsnes/chip/dsp1/dsp1.cpp
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#define DSP1_CPP
|
||||||
|
|
||||||
|
#include "dsp1.hpp"
|
||||||
|
#include "dsp1emu.cpp"
|
||||||
|
|
||||||
|
void DSP1::init() {}
|
||||||
|
void DSP1::enable() {}
|
||||||
|
|
||||||
|
void DSP1::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP1::reset() {
|
||||||
|
dsp1.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* addr_decode()
|
||||||
|
* determine whether address is accessing
|
||||||
|
* data register (DR) or status register (SR)
|
||||||
|
* -- 0 (false) = DR
|
||||||
|
* -- 1 (true ) = SR
|
||||||
|
*
|
||||||
|
* note: there is no need to bounds check addresses,
|
||||||
|
* as memory mapper will not allow DSP1 accesses outside
|
||||||
|
* of expected ranges
|
||||||
|
*****/
|
||||||
|
bool DSP1::addr_decode(uint16 addr) {
|
||||||
|
switch(cartridge.dsp1_mapper()) {
|
||||||
|
case Cartridge::DSP1LoROM1MB: {
|
||||||
|
//$[20-3f]:[8000-bfff] = DR, $[20-3f]:[c000-ffff] = SR
|
||||||
|
return (addr >= 0xc000);
|
||||||
|
}
|
||||||
|
|
||||||
|
case Cartridge::DSP1LoROM2MB: {
|
||||||
|
//$[60-6f]:[0000-3fff] = DR, $[60-6f]:[4000-7fff] = SR
|
||||||
|
return (addr >= 0x4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
case Cartridge::DSP1HiROM: {
|
||||||
|
//$[00-1f]:[6000-6fff] = DR, $[00-1f]:[7000-7fff] = SR
|
||||||
|
return (addr >= 0x7000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP1::read(unsigned addr) {
|
||||||
|
return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP1::write(unsigned addr, uint8 data) {
|
||||||
|
if(addr_decode(addr) == 0) {
|
||||||
|
dsp1.setDr(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
bsnes/chip/dsp1/dsp1.hpp
Executable file
18
bsnes/chip/dsp1/dsp1.hpp
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#include "dsp1emu.hpp"
|
||||||
|
|
||||||
|
class DSP1 : public Memory {
|
||||||
|
private:
|
||||||
|
Dsp1 dsp1;
|
||||||
|
bool addr_decode(uint16 addr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP1 dsp1;
|
||||||
1625
bsnes/chip/dsp1/dsp1emu.cpp
Executable file
1625
bsnes/chip/dsp1/dsp1emu.cpp
Executable file
File diff suppressed because it is too large
Load Diff
127
bsnes/chip/dsp1/dsp1emu.hpp
Executable file
127
bsnes/chip/dsp1/dsp1emu.hpp
Executable file
@ -0,0 +1,127 @@
|
|||||||
|
// DSP-1's emulation code
|
||||||
|
//
|
||||||
|
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
|
||||||
|
// Date: June 2006
|
||||||
|
|
||||||
|
#ifndef __DSP1EMUL_H
|
||||||
|
#define __DSP1EMUL_H
|
||||||
|
|
||||||
|
#define DSP1_VERSION 0x0102
|
||||||
|
|
||||||
|
class Dsp1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// The DSP-1 status register has 16 bits, but only
|
||||||
|
// the upper 8 bits can be accessed from an external device, so all these
|
||||||
|
// positions are referred to the upper byte (bits D8 to D15)
|
||||||
|
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
|
||||||
|
|
||||||
|
// According to Overload's docs, these are the meanings of the flags:
|
||||||
|
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
|
||||||
|
// 0: Data transfer to and from the DSP-1 is 16 bits.
|
||||||
|
// 1: Data transfer to and from the DSP-1 is 8 bits.
|
||||||
|
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
|
||||||
|
// 0: Data transfer has terminated.
|
||||||
|
// 1: Data transfer in progress.
|
||||||
|
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
|
||||||
|
// 0: Internal Data Register Transfer.
|
||||||
|
// 1: External Data Register Transfer.
|
||||||
|
|
||||||
|
Dsp1();
|
||||||
|
uint8 getSr(); // return the status register's high byte
|
||||||
|
uint8 getDr();
|
||||||
|
void setDr(uint8 iDr);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
|
||||||
|
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
void (Dsp1::*callback)(int16 *, int16 *);
|
||||||
|
unsigned int reads;
|
||||||
|
unsigned int writes;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Command mCommandTable[];
|
||||||
|
static const int16 MaxAZS_Exp[16];
|
||||||
|
static const int16 SinTable[];
|
||||||
|
static const int16 MulTable[];
|
||||||
|
static const uint16 DataRom[];
|
||||||
|
|
||||||
|
struct SharedData { // some RAM variables shared between commands
|
||||||
|
int16 MatrixA[3][3]; // attitude matrix A
|
||||||
|
int16 MatrixB[3][3];
|
||||||
|
int16 MatrixC[3][3];
|
||||||
|
int16 CentreX, CentreY, CentreZ; // center of projection
|
||||||
|
int16 CentreZ_C, CentreZ_E;
|
||||||
|
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
|
||||||
|
int16 Les, C_Les, E_Les;
|
||||||
|
int16 SinAas, CosAas;
|
||||||
|
int16 SinAzs, CosAzs;
|
||||||
|
int16 SinAZS, CosAZS;
|
||||||
|
int16 SecAZS_C1, SecAZS_E1;
|
||||||
|
int16 SecAZS_C2, SecAZS_E2;
|
||||||
|
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
|
||||||
|
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
|
||||||
|
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
|
||||||
|
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
|
||||||
|
|
||||||
|
} shared;
|
||||||
|
|
||||||
|
uint8 mSr; // status register
|
||||||
|
int mSrLowByteAccess;
|
||||||
|
uint16 mDr; // "internal" representation of the data register
|
||||||
|
FsmMajorState mFsmMajorState; // current major state of the FSM
|
||||||
|
uint8 mCommand; // current command processed by the FSM
|
||||||
|
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
|
||||||
|
int16 mReadBuffer[MAX_READS];
|
||||||
|
int16 mWriteBuffer[MAX_WRITES];
|
||||||
|
bool mFreeze; // need explanation? ;)
|
||||||
|
|
||||||
|
void fsmStep(bool read, uint8 &data); // FSM logic
|
||||||
|
|
||||||
|
// commands
|
||||||
|
void memoryTest(int16 *input, int16 *output);
|
||||||
|
void memoryDump(int16 *input, int16 *output);
|
||||||
|
void memorySize(int16 *input, int16 *output);
|
||||||
|
void multiply(int16* input, int16* output);
|
||||||
|
void multiply2(int16* input, int16* output);
|
||||||
|
void inverse(int16 *input, int16 *output);
|
||||||
|
void triangle(int16 *input, int16 *output);
|
||||||
|
void radius(int16 *input, int16 *output);
|
||||||
|
void range(int16 *input, int16 *output);
|
||||||
|
void range2(int16 *input, int16 *output);
|
||||||
|
void distance(int16 *input, int16 *output);
|
||||||
|
void rotate(int16 *input, int16 *output);
|
||||||
|
void polar(int16 *input, int16 *output);
|
||||||
|
void attitudeA(int16 *input, int16 *output);
|
||||||
|
void attitudeB(int16 *input, int16 *output);
|
||||||
|
void attitudeC(int16 *input, int16 *output);
|
||||||
|
void objectiveA(int16 *input, int16 *output);
|
||||||
|
void objectiveB(int16 *input, int16 *output);
|
||||||
|
void objectiveC(int16 *input, int16 *output);
|
||||||
|
void subjectiveA(int16 *input, int16 *output);
|
||||||
|
void subjectiveB(int16 *input, int16 *output);
|
||||||
|
void subjectiveC(int16 *input, int16 *output);
|
||||||
|
void scalarA(int16 *input, int16 *output);
|
||||||
|
void scalarB(int16 *input, int16 *output);
|
||||||
|
void scalarC(int16 *input, int16 *output);
|
||||||
|
void gyrate(int16 *input, int16 *output);
|
||||||
|
void parameter(int16 *input, int16 *output);
|
||||||
|
void raster(int16 *input, int16 *output);
|
||||||
|
void target(int16 *input, int16 *output);
|
||||||
|
void project(int16 *input, int16 *output);
|
||||||
|
|
||||||
|
// auxiliar functions
|
||||||
|
int16 sin(int16 Angle);
|
||||||
|
int16 cos(int16 Angle);
|
||||||
|
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
|
||||||
|
int16 denormalizeAndClip(int16 C, int16 E);
|
||||||
|
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
|
||||||
|
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
|
||||||
|
int16 shiftR(int16 C, int16 E);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
136
bsnes/chip/dsp2/dsp2.cpp
Executable file
136
bsnes/chip/dsp2/dsp2.cpp
Executable file
@ -0,0 +1,136 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define DSP2_CPP
|
||||||
|
|
||||||
|
#include "dsp2.hpp"
|
||||||
|
#include "dsp2_op.cpp"
|
||||||
|
|
||||||
|
void DSP2::init() {}
|
||||||
|
void DSP2::enable() {}
|
||||||
|
|
||||||
|
void DSP2::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::reset() {
|
||||||
|
status.waiting_for_command = true;
|
||||||
|
status.in_count = 0;
|
||||||
|
status.in_index = 0;
|
||||||
|
status.out_count = 0;
|
||||||
|
status.out_index = 0;
|
||||||
|
|
||||||
|
status.op05transparent = 0;
|
||||||
|
status.op05haslen = false;
|
||||||
|
status.op05len = 0;
|
||||||
|
status.op06haslen = false;
|
||||||
|
status.op06len = 0;
|
||||||
|
status.op09word1 = 0;
|
||||||
|
status.op09word2 = 0;
|
||||||
|
status.op0dhaslen = false;
|
||||||
|
status.op0doutlen = 0;
|
||||||
|
status.op0dinlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP2::read(unsigned addr) {
|
||||||
|
uint8 r = 0xff;
|
||||||
|
if(status.out_count) {
|
||||||
|
r = status.output[status.out_index++];
|
||||||
|
status.out_index &= 511;
|
||||||
|
if(status.out_count == status.out_index) {
|
||||||
|
status.out_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::write(unsigned addr, uint8 data) {
|
||||||
|
if(status.waiting_for_command) {
|
||||||
|
status.command = data;
|
||||||
|
status.in_index = 0;
|
||||||
|
status.waiting_for_command = false;
|
||||||
|
|
||||||
|
switch(data) {
|
||||||
|
case 0x01: status.in_count = 32; break;
|
||||||
|
case 0x03: status.in_count = 1; break;
|
||||||
|
case 0x05: status.in_count = 1; break;
|
||||||
|
case 0x06: status.in_count = 1; break;
|
||||||
|
case 0x07: break;
|
||||||
|
case 0x08: break;
|
||||||
|
case 0x09: status.in_count = 4; break;
|
||||||
|
case 0x0d: status.in_count = 2; break;
|
||||||
|
case 0x0f: status.in_count = 0; break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status.parameters[status.in_index++] = data;
|
||||||
|
status.in_index &= 511;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.in_count == status.in_index) {
|
||||||
|
status.waiting_for_command = true;
|
||||||
|
status.out_index = 0;
|
||||||
|
switch(status.command) {
|
||||||
|
case 0x01: {
|
||||||
|
status.out_count = 32;
|
||||||
|
op01();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x03: {
|
||||||
|
op03();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x05: {
|
||||||
|
if(status.op05haslen) {
|
||||||
|
status.op05haslen = false;
|
||||||
|
status.out_count = status.op05len;
|
||||||
|
op05();
|
||||||
|
} else {
|
||||||
|
status.op05len = status.parameters[0];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = status.op05len * 2;
|
||||||
|
status.op05haslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x06: {
|
||||||
|
if(status.op06haslen) {
|
||||||
|
status.op06haslen = false;
|
||||||
|
status.out_count = status.op06len;
|
||||||
|
op06();
|
||||||
|
} else {
|
||||||
|
status.op06len = status.parameters[0];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = status.op06len;
|
||||||
|
status.op06haslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x07: break;
|
||||||
|
case 0x08: break;
|
||||||
|
|
||||||
|
case 0x09: {
|
||||||
|
op09();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x0d: {
|
||||||
|
if(status.op0dhaslen) {
|
||||||
|
status.op0dhaslen = false;
|
||||||
|
status.out_count = status.op0doutlen;
|
||||||
|
op0d();
|
||||||
|
} else {
|
||||||
|
status.op0dinlen = status.parameters[0];
|
||||||
|
status.op0doutlen = status.parameters[1];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = (status.op0dinlen + 1) >> 1;
|
||||||
|
status.op0dhaslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x0f: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DSP2::DSP2() {}
|
||||||
|
DSP2::~DSP2() {}
|
||||||
44
bsnes/chip/dsp2/dsp2.hpp
Executable file
44
bsnes/chip/dsp2/dsp2.hpp
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
class DSP2 : public Memory {
|
||||||
|
public:
|
||||||
|
struct {
|
||||||
|
bool waiting_for_command;
|
||||||
|
unsigned command;
|
||||||
|
unsigned in_count, in_index;
|
||||||
|
unsigned out_count, out_index;
|
||||||
|
|
||||||
|
uint8 parameters[512];
|
||||||
|
uint8 output[512];
|
||||||
|
|
||||||
|
uint8 op05transparent;
|
||||||
|
bool op05haslen;
|
||||||
|
int op05len;
|
||||||
|
bool op06haslen;
|
||||||
|
int op06len;
|
||||||
|
uint16 op09word1;
|
||||||
|
uint16 op09word2;
|
||||||
|
bool op0dhaslen;
|
||||||
|
int op0doutlen;
|
||||||
|
int op0dinlen;
|
||||||
|
} status;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
DSP2();
|
||||||
|
~DSP2();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void op01();
|
||||||
|
void op03();
|
||||||
|
void op05();
|
||||||
|
void op06();
|
||||||
|
void op09();
|
||||||
|
void op0d();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP2 dsp2;
|
||||||
177
bsnes/chip/dsp2/dsp2_op.cpp
Executable file
177
bsnes/chip/dsp2/dsp2_op.cpp
Executable file
@ -0,0 +1,177 @@
|
|||||||
|
#ifdef DSP2_CPP
|
||||||
|
|
||||||
|
//convert bitmap to bitplane tile
|
||||||
|
void DSP2::op01() {
|
||||||
|
//op01 size is always 32 bytes input and output
|
||||||
|
//the hardware does strange things if you vary the size
|
||||||
|
|
||||||
|
unsigned char c0, c1, c2, c3;
|
||||||
|
unsigned char *p1 = status.parameters;
|
||||||
|
unsigned char *p2a = status.output;
|
||||||
|
unsigned char *p2b = status.output + 16; //halfway
|
||||||
|
|
||||||
|
//process 8 blocks of 4 bytes each
|
||||||
|
for(int j = 0; j < 8; j++) {
|
||||||
|
c0 = *p1++;
|
||||||
|
c1 = *p1++;
|
||||||
|
c2 = *p1++;
|
||||||
|
c3 = *p1++;
|
||||||
|
|
||||||
|
*p2a++ = (c0 & 0x10) << 3 |
|
||||||
|
(c0 & 0x01) << 6 |
|
||||||
|
(c1 & 0x10) << 1 |
|
||||||
|
(c1 & 0x01) << 4 |
|
||||||
|
(c2 & 0x10) >> 1 |
|
||||||
|
(c2 & 0x01) << 2 |
|
||||||
|
(c3 & 0x10) >> 3 |
|
||||||
|
(c3 & 0x01);
|
||||||
|
|
||||||
|
*p2a++ = (c0 & 0x20) << 2 |
|
||||||
|
(c0 & 0x02) << 5 |
|
||||||
|
(c1 & 0x20) |
|
||||||
|
(c1 & 0x02) << 3 |
|
||||||
|
(c2 & 0x20) >> 2 |
|
||||||
|
(c2 & 0x02) << 1 |
|
||||||
|
(c3 & 0x20) >> 4 |
|
||||||
|
(c3 & 0x02) >> 1;
|
||||||
|
|
||||||
|
*p2b++ = (c0 & 0x40) << 1 |
|
||||||
|
(c0 & 0x04) << 4 |
|
||||||
|
(c1 & 0x40) >> 1 |
|
||||||
|
(c1 & 0x04) << 2 |
|
||||||
|
(c2 & 0x40) >> 3 |
|
||||||
|
(c2 & 0x04) |
|
||||||
|
(c3 & 0x40) >> 5 |
|
||||||
|
(c3 & 0x04) >> 2;
|
||||||
|
|
||||||
|
*p2b++ = (c0 & 0x80) |
|
||||||
|
(c0 & 0x08) << 3 |
|
||||||
|
(c1 & 0x80) >> 2 |
|
||||||
|
(c1 & 0x08) << 1 |
|
||||||
|
(c2 & 0x80) >> 4 |
|
||||||
|
(c2 & 0x08) >> 1 |
|
||||||
|
(c3 & 0x80) >> 6 |
|
||||||
|
(c3 & 0x08) >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//set transparent color
|
||||||
|
void DSP2::op03() {
|
||||||
|
status.op05transparent = status.parameters[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//replace bitmap using transparent color
|
||||||
|
void DSP2::op05() {
|
||||||
|
uint8 color;
|
||||||
|
// Overlay bitmap with transparency.
|
||||||
|
// Input:
|
||||||
|
//
|
||||||
|
// Bitmap 1: i[0] <=> i[size-1]
|
||||||
|
// Bitmap 2: i[size] <=> i[2*size-1]
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// Bitmap 3: o[0] <=> o[size-1]
|
||||||
|
//
|
||||||
|
// Processing:
|
||||||
|
//
|
||||||
|
// Process all 4-bit pixels (nibbles) in the bitmap
|
||||||
|
//
|
||||||
|
// if ( BM2_pixel == transparent_color )
|
||||||
|
// pixelout = BM1_pixel
|
||||||
|
// else
|
||||||
|
// pixelout = BM2_pixel
|
||||||
|
|
||||||
|
// The max size bitmap is limited to 255 because the size parameter is a byte
|
||||||
|
// I think size=0 is an error. The behavior of the chip on size=0 is to
|
||||||
|
// return the last value written to DR if you read DR on Op05 with
|
||||||
|
// size = 0. I don't think it's worth implementing this quirk unless it's
|
||||||
|
// proven necessary.
|
||||||
|
|
||||||
|
unsigned char c1, c2;
|
||||||
|
unsigned char *p1 = status.parameters;
|
||||||
|
unsigned char *p2 = status.parameters + status.op05len;
|
||||||
|
unsigned char *p3 = status.output;
|
||||||
|
|
||||||
|
color = status.op05transparent & 0x0f;
|
||||||
|
|
||||||
|
for(int n = 0; n < status.op05len; n++) {
|
||||||
|
c1 = *p1++;
|
||||||
|
c2 = *p2++;
|
||||||
|
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
|
||||||
|
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//reverse bitmap
|
||||||
|
void DSP2::op06() {
|
||||||
|
// Input:
|
||||||
|
// size
|
||||||
|
// bitmap
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
|
||||||
|
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiply
|
||||||
|
void DSP2::op09() {
|
||||||
|
status.out_count = 4;
|
||||||
|
|
||||||
|
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
|
||||||
|
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
|
||||||
|
|
||||||
|
uint32 r;
|
||||||
|
r = status.op09word1 * status.op09word2;
|
||||||
|
status.output[0] = r;
|
||||||
|
status.output[1] = r >> 8;
|
||||||
|
status.output[2] = r >> 16;
|
||||||
|
status.output[3] = r >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
//scale bitmap
|
||||||
|
void DSP2::op0d() {
|
||||||
|
// Bit accurate hardware algorithm - uses fixed point math
|
||||||
|
// This should match the DSP2 Op0D output exactly
|
||||||
|
// I wouldn't recommend using this unless you're doing hardware debug.
|
||||||
|
// In some situations it has small visual artifacts that
|
||||||
|
// are not readily apparent on a TV screen but show up clearly
|
||||||
|
// on a monitor. Use Overload's scaling instead.
|
||||||
|
// This is for hardware verification testing.
|
||||||
|
//
|
||||||
|
// One note: the HW can do odd byte scaling but since we divide
|
||||||
|
// by two to get the count of bytes this won't work well for
|
||||||
|
// odd byte scaling (in any of the current algorithm implementations).
|
||||||
|
// So far I haven't seen Dungeon Master use it.
|
||||||
|
// If it does we can adjust the parameters and code to work with it
|
||||||
|
|
||||||
|
uint32 multiplier; // Any size int >= 32-bits
|
||||||
|
uint32 pixloc; // match size of multiplier
|
||||||
|
int i, j;
|
||||||
|
uint8 pixelarray[512];
|
||||||
|
if(status.op0dinlen <= status.op0doutlen) {
|
||||||
|
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
|
||||||
|
} else {
|
||||||
|
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixloc = 0;
|
||||||
|
for(i = 0; i < status.op0doutlen * 2; i++) {
|
||||||
|
j = pixloc >> 16;
|
||||||
|
|
||||||
|
if(j & 1) {
|
||||||
|
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
|
||||||
|
} else {
|
||||||
|
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixloc += multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < status.op0doutlen; i++) {
|
||||||
|
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
35
bsnes/chip/dsp3/dsp3.cpp
Executable file
35
bsnes/chip/dsp3/dsp3.cpp
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define DSP3_CPP
|
||||||
|
|
||||||
|
#include "dsp3.hpp"
|
||||||
|
namespace DSP3i {
|
||||||
|
#define bool8 uint8
|
||||||
|
#include "dsp3emu.c"
|
||||||
|
#undef bool8
|
||||||
|
};
|
||||||
|
|
||||||
|
void DSP3::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::reset() {
|
||||||
|
DSP3i::DSP3_Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP3::read(unsigned addr) {
|
||||||
|
DSP3i::dsp3_address = addr & 0xffff;
|
||||||
|
DSP3i::DSP3GetByte();
|
||||||
|
return DSP3i::dsp3_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::write(unsigned addr, uint8 data) {
|
||||||
|
DSP3i::dsp3_address = addr & 0xffff;
|
||||||
|
DSP3i::dsp3_byte = data;
|
||||||
|
DSP3i::DSP3SetByte();
|
||||||
|
}
|
||||||
12
bsnes/chip/dsp3/dsp3.hpp
Executable file
12
bsnes/chip/dsp3/dsp3.hpp
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
class DSP3 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP3 dsp3;
|
||||||
1146
bsnes/chip/dsp3/dsp3emu.c
Executable file
1146
bsnes/chip/dsp3/dsp3emu.c
Executable file
File diff suppressed because it is too large
Load Diff
55
bsnes/chip/dsp4/dsp4.cpp
Executable file
55
bsnes/chip/dsp4/dsp4.cpp
Executable file
@ -0,0 +1,55 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define DSP4_CPP
|
||||||
|
|
||||||
|
#include "dsp4.hpp"
|
||||||
|
namespace DSP4i {
|
||||||
|
inline uint16 READ_WORD(uint8 *addr) {
|
||||||
|
return (addr[0]) + (addr[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 READ_DWORD(uint8 *addr) {
|
||||||
|
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WRITE_WORD(uint8 *addr, uint16 data) {
|
||||||
|
addr[0] = data;
|
||||||
|
addr[1] = data >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define bool8 uint8
|
||||||
|
#include "dsp4emu.c"
|
||||||
|
#undef bool8
|
||||||
|
};
|
||||||
|
|
||||||
|
void DSP4::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP4::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP4::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP4::reset() {
|
||||||
|
DSP4i::InitDSP4();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP4::read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
if(addr < 0xc000) {
|
||||||
|
DSP4i::dsp4_address = addr;
|
||||||
|
DSP4i::DSP4GetByte();
|
||||||
|
return DSP4i::dsp4_byte;
|
||||||
|
}
|
||||||
|
return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP4::write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
if(addr < 0xc000) {
|
||||||
|
DSP4i::dsp4_address = addr;
|
||||||
|
DSP4i::dsp4_byte = data;
|
||||||
|
DSP4i::DSP4SetByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
bsnes/chip/dsp4/dsp4.hpp
Executable file
12
bsnes/chip/dsp4/dsp4.hpp
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
class DSP4 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP4 dsp4;
|
||||||
2150
bsnes/chip/dsp4/dsp4emu.c
Executable file
2150
bsnes/chip/dsp4/dsp4emu.c
Executable file
File diff suppressed because it is too large
Load Diff
108
bsnes/chip/dsp4/dsp4emu.h
Executable file
108
bsnes/chip/dsp4/dsp4emu.h
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
//DSP-4 emulator code
|
||||||
|
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
|
||||||
|
|
||||||
|
#ifndef DSP4EMU_H
|
||||||
|
#define DSP4EMU_H
|
||||||
|
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
#define TRUE true
|
||||||
|
#define FALSE false
|
||||||
|
|
||||||
|
struct DSP4_t
|
||||||
|
{
|
||||||
|
bool8 waiting4command;
|
||||||
|
bool8 half_command;
|
||||||
|
uint16 command;
|
||||||
|
uint32 in_count;
|
||||||
|
uint32 in_index;
|
||||||
|
uint32 out_count;
|
||||||
|
uint32 out_index;
|
||||||
|
uint8 parameters[512];
|
||||||
|
uint8 output[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct DSP4_t DSP4;
|
||||||
|
|
||||||
|
struct DSP4_vars_t
|
||||||
|
{
|
||||||
|
// op control
|
||||||
|
int8 DSP4_Logic; // controls op flow
|
||||||
|
|
||||||
|
|
||||||
|
// projection format
|
||||||
|
int16 lcv; // loop-control variable
|
||||||
|
int16 distance; // z-position into virtual world
|
||||||
|
int16 raster; // current raster line
|
||||||
|
int16 segments; // number of raster lines drawn
|
||||||
|
|
||||||
|
// 1.15.16 or 1.15.0 [sign, integer, fraction]
|
||||||
|
int32 world_x; // line of x-projection in world
|
||||||
|
int32 world_y; // line of y-projection in world
|
||||||
|
int32 world_dx; // projection line x-delta
|
||||||
|
int32 world_dy; // projection line y-delta
|
||||||
|
int16 world_ddx; // x-delta increment
|
||||||
|
int16 world_ddy; // y-delta increment
|
||||||
|
int32 world_xenv; // world x-shaping factor
|
||||||
|
int16 world_yofs; // world y-vertical scroll
|
||||||
|
|
||||||
|
int16 view_x1; // current viewer-x
|
||||||
|
int16 view_y1; // current viewer-y
|
||||||
|
int16 view_x2; // future viewer-x
|
||||||
|
int16 view_y2; // future viewer-y
|
||||||
|
int16 view_dx; // view x-delta factor
|
||||||
|
int16 view_dy; // view y-delta factor
|
||||||
|
int16 view_xofs1; // current viewer x-vertical scroll
|
||||||
|
int16 view_yofs1; // current viewer y-vertical scroll
|
||||||
|
int16 view_xofs2; // future viewer x-vertical scroll
|
||||||
|
int16 view_yofs2; // future viewer y-vertical scroll
|
||||||
|
int16 view_yofsenv; // y-scroll shaping factor
|
||||||
|
int16 view_turnoff_x; // road turnoff data
|
||||||
|
int16 view_turnoff_dx; // road turnoff delta factor
|
||||||
|
|
||||||
|
|
||||||
|
// drawing area
|
||||||
|
|
||||||
|
int16 viewport_cx; // x-center of viewport window
|
||||||
|
int16 viewport_cy; // y-center of render window
|
||||||
|
int16 viewport_left; // x-left of viewport
|
||||||
|
int16 viewport_right; // x-right of viewport
|
||||||
|
int16 viewport_top; // y-top of viewport
|
||||||
|
int16 viewport_bottom; // y-bottom of viewport
|
||||||
|
|
||||||
|
|
||||||
|
// sprite structure
|
||||||
|
|
||||||
|
int16 sprite_x; // projected x-pos of sprite
|
||||||
|
int16 sprite_y; // projected y-pos of sprite
|
||||||
|
int16 sprite_attr; // obj attributes
|
||||||
|
bool8 sprite_size; // sprite size: 8x8 or 16x16
|
||||||
|
int16 sprite_clipy; // visible line to clip pixels off
|
||||||
|
int16 sprite_count;
|
||||||
|
|
||||||
|
// generic projection variables designed for
|
||||||
|
// two solid polygons + two polygon sides
|
||||||
|
|
||||||
|
int16 poly_clipLf[2][2]; // left clip boundary
|
||||||
|
int16 poly_clipRt[2][2]; // right clip boundary
|
||||||
|
int16 poly_ptr[2][2]; // HDMA structure pointers
|
||||||
|
int16 poly_raster[2][2]; // current raster line below horizon
|
||||||
|
int16 poly_top[2][2]; // top clip boundary
|
||||||
|
int16 poly_bottom[2][2]; // bottom clip boundary
|
||||||
|
int16 poly_cx[2][2]; // center for left/right points
|
||||||
|
int16 poly_start[2]; // current projection points
|
||||||
|
int16 poly_plane[2]; // previous z-plane distance
|
||||||
|
|
||||||
|
|
||||||
|
// OAM
|
||||||
|
int16 OAM_attr[16]; // OAM (size,MSB) data
|
||||||
|
int16 OAM_index; // index into OAM table
|
||||||
|
int16 OAM_bits; // offset into OAM table
|
||||||
|
|
||||||
|
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
|
||||||
|
int16 OAM_Row[32]; // current number of tiles per row
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct DSP4_vars_t DSP4_vars;
|
||||||
|
|
||||||
|
#endif
|
||||||
72
bsnes/chip/obc1/obc1.cpp
Executable file
72
bsnes/chip/obc1/obc1.cpp
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#include "obc1.hpp"
|
||||||
|
|
||||||
|
void OBC1::init() {}
|
||||||
|
void OBC1::enable() {}
|
||||||
|
|
||||||
|
void OBC1::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBC1::reset() {
|
||||||
|
for(unsigned i = 0x0000; i <= 0x1fff; i++) ram_write(i, 0xff);
|
||||||
|
|
||||||
|
status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00;
|
||||||
|
status.address = (ram_read(0x1ff6) & 0x7f);
|
||||||
|
status.shift = (ram_read(0x1ff6) & 3) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 OBC1::read(unsigned addr) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
if((addr & 0x1ff8) != 0x1ff0) return ram_read(addr);
|
||||||
|
|
||||||
|
switch(addr) { default: //never used, avoids compiler warning
|
||||||
|
case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0);
|
||||||
|
case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1);
|
||||||
|
case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2);
|
||||||
|
case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3);
|
||||||
|
case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200);
|
||||||
|
case 0x1ff5: case 0x1ff6: case 0x1ff7: return ram_read(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBC1::write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
if((addr & 0x1ff8) != 0x1ff0) return ram_write(addr, data);
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); break;
|
||||||
|
case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); break;
|
||||||
|
case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); break;
|
||||||
|
case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); break;
|
||||||
|
case 0x1ff4: {
|
||||||
|
uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200);
|
||||||
|
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
|
||||||
|
ram_write(status.baseptr + (status.address >> 2) + 0x200, temp);
|
||||||
|
} break;
|
||||||
|
case 0x1ff5: {
|
||||||
|
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
|
||||||
|
ram_write(addr, data);
|
||||||
|
} break;
|
||||||
|
case 0x1ff6: {
|
||||||
|
status.address = (data & 0x7f);
|
||||||
|
status.shift = (data & 3) << 1;
|
||||||
|
ram_write(addr, data);
|
||||||
|
} break;
|
||||||
|
case 0x1ff7: {
|
||||||
|
ram_write(addr, data);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 OBC1::ram_read(unsigned addr) {
|
||||||
|
return memory::cartram.read(addr & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBC1::ram_write(unsigned addr, uint8 data) {
|
||||||
|
memory::cartram.write(addr & 0x1fff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
OBC1::OBC1() {}
|
||||||
|
OBC1::~OBC1() {}
|
||||||
25
bsnes/chip/obc1/obc1.hpp
Executable file
25
bsnes/chip/obc1/obc1.hpp
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
class OBC1 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
OBC1();
|
||||||
|
~OBC1();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram_read(unsigned addr);
|
||||||
|
void ram_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16 address;
|
||||||
|
uint16 baseptr;
|
||||||
|
uint16 shift;
|
||||||
|
} status;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern OBC1 obc1;
|
||||||
158
bsnes/chip/sdd1/sdd1.cpp
Executable file
158
bsnes/chip/sdd1/sdd1.cpp
Executable file
@ -0,0 +1,158 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#define SDD1_CPP
|
||||||
|
|
||||||
|
#include "sdd1.hpp"
|
||||||
|
#include "sdd1emu.cpp"
|
||||||
|
|
||||||
|
void SDD1::init() {}
|
||||||
|
|
||||||
|
void SDD1::enable() {
|
||||||
|
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
||||||
|
//buffer address and transfer size information for use in SDD1::read()
|
||||||
|
for(unsigned i = 0x4300; i <= 0x437f; i++) {
|
||||||
|
cpu_mmio[i & 0x7f] = memory::mmio.get(i);
|
||||||
|
memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//hook S-DD1 MMIO registers
|
||||||
|
for(unsigned i = 0x4800; i <= 0x4807; i++) {
|
||||||
|
memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDD1::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDD1::reset() {
|
||||||
|
sdd1_enable = 0x00;
|
||||||
|
xfer_enable = 0x00;
|
||||||
|
|
||||||
|
mmc[0] = 0 << 20;
|
||||||
|
mmc[1] = 1 << 20;
|
||||||
|
mmc[2] = 2 << 20;
|
||||||
|
mmc[3] = 3 << 20;
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
dma[i].addr = 0;
|
||||||
|
dma[i].size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.ready = false;
|
||||||
|
|
||||||
|
bus.map(Bus::MapDirect, 0xc0, 0xff, 0x0000, 0xffff, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SDD1::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if((addr & 0x4380) == 0x4300) {
|
||||||
|
return cpu_mmio[addr & 0x7f]->mmio_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x4804: return (mmc[0] >> 20) & 7;
|
||||||
|
case 0x4805: return (mmc[1] >> 20) & 7;
|
||||||
|
case 0x4806: return (mmc[2] >> 20) & 7;
|
||||||
|
case 0x4807: return (mmc[3] >> 20) & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if((addr & 0x4380) == 0x4300) {
|
||||||
|
unsigned channel = (addr >> 4) & 7;
|
||||||
|
switch(addr & 15) {
|
||||||
|
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
|
||||||
|
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
|
||||||
|
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
|
||||||
|
|
||||||
|
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
|
||||||
|
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
|
||||||
|
}
|
||||||
|
return cpu_mmio[addr & 0x7f]->mmio_write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x4800: sdd1_enable = data; break;
|
||||||
|
case 0x4801: xfer_enable = data; break;
|
||||||
|
|
||||||
|
case 0x4804: mmc[0] = (data & 7) << 20; break;
|
||||||
|
case 0x4805: mmc[1] = (data & 7) << 20; break;
|
||||||
|
case 0x4806: mmc[2] = (data & 7) << 20; break;
|
||||||
|
case 0x4807: mmc[3] = (data & 7) << 20; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//SDD1::read() is mapped to $[c0-ff]:[0000-ffff]
|
||||||
|
//the design is meant to be as close to the hardware design as possible, thus this code
|
||||||
|
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
|
||||||
|
//
|
||||||
|
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
|
||||||
|
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
|
||||||
|
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
|
||||||
|
//it could see $420b writes (eg it would know when the transfer should begin.)
|
||||||
|
//
|
||||||
|
//the hardware needs a way to distinguish program code after $4801 writes from DMA
|
||||||
|
//decompression that follows soon after.
|
||||||
|
//
|
||||||
|
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
|
||||||
|
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
|
||||||
|
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
|
||||||
|
//
|
||||||
|
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
||||||
|
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
||||||
|
uint8 SDD1::read(unsigned addr) {
|
||||||
|
if(sdd1_enable & xfer_enable) {
|
||||||
|
//at least one channel has S-DD1 decompression enabled ...
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(sdd1_enable & xfer_enable & (1 << i)) {
|
||||||
|
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
|
||||||
|
if(addr == dma[i].addr) {
|
||||||
|
if(!buffer.ready) {
|
||||||
|
//first byte read for channel performs full decompression.
|
||||||
|
//this really should stream byte-by-byte, but it's not necessary since the size is known
|
||||||
|
buffer.offset = 0;
|
||||||
|
buffer.size = dma[i].size ? dma[i].size : 65536;
|
||||||
|
|
||||||
|
//sdd1emu calls this function; it needs to access uncompressed data;
|
||||||
|
//so temporarily disable decompression mode for decompress() call.
|
||||||
|
uint8 temp = sdd1_enable;
|
||||||
|
sdd1_enable = false;
|
||||||
|
sdd1emu.decompress(addr, buffer.size, buffer.data);
|
||||||
|
sdd1_enable = temp;
|
||||||
|
|
||||||
|
buffer.ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
|
||||||
|
uint8 data = buffer.data[(uint16)buffer.offset++];
|
||||||
|
if(buffer.offset >= buffer.size) {
|
||||||
|
buffer.ready = false;
|
||||||
|
xfer_enable &= ~(1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} //address matched
|
||||||
|
} //channel enabled
|
||||||
|
} //channel loop
|
||||||
|
} //S-DD1 decompressor enabled
|
||||||
|
|
||||||
|
//S-DD1 decompression mode inactive; return ROM data
|
||||||
|
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDD1::write(unsigned addr, uint8 data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SDD1::SDD1() {
|
||||||
|
buffer.data = new uint8[65536];
|
||||||
|
}
|
||||||
|
|
||||||
|
SDD1::~SDD1() {
|
||||||
|
delete[] buffer.data;
|
||||||
|
}
|
||||||
40
bsnes/chip/sdd1/sdd1.hpp
Executable file
40
bsnes/chip/sdd1/sdd1.hpp
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#include "sdd1emu.hpp"
|
||||||
|
|
||||||
|
class SDD1 : public MMIO, public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
SDD1();
|
||||||
|
~SDD1();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
|
||||||
|
|
||||||
|
uint8 sdd1_enable; //channel bit-mask
|
||||||
|
uint8 xfer_enable; //channel bit-mask
|
||||||
|
unsigned mmc[4]; //memory map controller ROM indices
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||||
|
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||||
|
} dma[8];
|
||||||
|
|
||||||
|
SDD1emu sdd1emu;
|
||||||
|
struct {
|
||||||
|
uint8 *data; //pointer to decompressed S-DD1 data (65536 bytes)
|
||||||
|
uint16 offset; //read index into S-DD1 decompression buffer
|
||||||
|
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
|
||||||
|
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
|
||||||
|
} buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SDD1 sdd1;
|
||||||
451
bsnes/chip/sdd1/sdd1emu.cpp
Executable file
451
bsnes/chip/sdd1/sdd1emu.cpp
Executable file
@ -0,0 +1,451 @@
|
|||||||
|
#ifdef SDD1_CPP
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
|
||||||
|
S-DD1'algorithm emulation code
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Author: Andreas Naive
|
||||||
|
Date: August 2003
|
||||||
|
Last update: October 2004
|
||||||
|
|
||||||
|
This code is Public Domain. There is no copyright holded by the author.
|
||||||
|
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||||
|
over this piece of intelectual work and the previous research that made it
|
||||||
|
possible, as recognized by most of the copyright laws around the world.
|
||||||
|
|
||||||
|
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||||
|
No responsability is assumed by the author in connection with it.
|
||||||
|
|
||||||
|
The author is greatly indebted with The Dumper, without whose help and
|
||||||
|
patience providing him with real S-DD1 data the research would have never been
|
||||||
|
possible. He also wish to note that in the very beggining of his research,
|
||||||
|
Neviksti had done some steps in the right direction. By last, the author is
|
||||||
|
indirectly indebted to all the people that worked and contributed in the
|
||||||
|
S-DD1 issue in the past.
|
||||||
|
|
||||||
|
An algorithm's documentation is available as a separate document.
|
||||||
|
The implementation is obvious when the algorithm is
|
||||||
|
understood.
|
||||||
|
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#define SDD1_read(__addr) (sdd1.read(__addr))
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_IM::prepareDecomp(uint32 in_buf) {
|
||||||
|
|
||||||
|
byte_ptr=in_buf;
|
||||||
|
bit_count=4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
uint8 SDD1_IM::getCodeword(uint8 code_len) {
|
||||||
|
|
||||||
|
uint8 codeword;
|
||||||
|
uint8 comp_count;
|
||||||
|
|
||||||
|
codeword = (SDD1_read(byte_ptr))<<bit_count;
|
||||||
|
|
||||||
|
++bit_count;
|
||||||
|
|
||||||
|
if (codeword & 0x80) {
|
||||||
|
codeword |= SDD1_read(byte_ptr+1)>>(9-bit_count);
|
||||||
|
bit_count+=code_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit_count & 0x08) {
|
||||||
|
byte_ptr++;
|
||||||
|
bit_count&=0x07;
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeword;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
|
||||||
|
IM(associatedIM)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_GCD::getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind) {
|
||||||
|
|
||||||
|
const uint8 run_count[] = {
|
||||||
|
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
|
||||||
|
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
|
||||||
|
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
|
||||||
|
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
|
||||||
|
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
|
||||||
|
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
|
||||||
|
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
|
||||||
|
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
|
||||||
|
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
|
||||||
|
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
|
||||||
|
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
|
||||||
|
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
|
||||||
|
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
|
||||||
|
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
|
||||||
|
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
|
||||||
|
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
|
||||||
|
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
|
||||||
|
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
|
||||||
|
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
|
||||||
|
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
|
||||||
|
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
|
||||||
|
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
|
||||||
|
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
|
||||||
|
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
|
||||||
|
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
|
||||||
|
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
|
||||||
|
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
|
||||||
|
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
|
||||||
|
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
|
||||||
|
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
|
||||||
|
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
|
||||||
|
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 codeword=IM->getCodeword(code_num);
|
||||||
|
|
||||||
|
if (codeword & 0x80) {
|
||||||
|
*LPSind=1;
|
||||||
|
*MPScount=run_count[codeword>>(code_num^0x07)];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*MPScount=(1<<code_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8 code) :
|
||||||
|
GCD(associatedGCD), code_num(code)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_BG::prepareDecomp(void) {
|
||||||
|
|
||||||
|
MPScount=0;
|
||||||
|
LPSind=0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
uint8 SDD1_BG::getBit(bool8 *endOfRun) {
|
||||||
|
|
||||||
|
uint8 bit;
|
||||||
|
|
||||||
|
if (!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
|
||||||
|
|
||||||
|
if (MPScount) {
|
||||||
|
bit=0;
|
||||||
|
MPScount--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bit=1;
|
||||||
|
LPSind=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MPScount || LPSind) (*endOfRun)=0;
|
||||||
|
else (*endOfRun)=1;
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||||
|
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||||
|
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||||
|
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7) {
|
||||||
|
|
||||||
|
BG[0]=associatedBG0;
|
||||||
|
BG[1]=associatedBG1;
|
||||||
|
BG[2]=associatedBG2;
|
||||||
|
BG[3]=associatedBG3;
|
||||||
|
BG[4]=associatedBG4;
|
||||||
|
BG[5]=associatedBG5;
|
||||||
|
BG[6]=associatedBG6;
|
||||||
|
BG[7]=associatedBG7;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
const SDD1_PEM::state SDD1_PEM::evolution_table[]={
|
||||||
|
{ 0,25,25},
|
||||||
|
{ 0, 2, 1},
|
||||||
|
{ 0, 3, 1},
|
||||||
|
{ 0, 4, 2},
|
||||||
|
{ 0, 5, 3},
|
||||||
|
{ 1, 6, 4},
|
||||||
|
{ 1, 7, 5},
|
||||||
|
{ 1, 8, 6},
|
||||||
|
{ 1, 9, 7},
|
||||||
|
{ 2,10, 8},
|
||||||
|
{ 2,11, 9},
|
||||||
|
{ 2,12,10},
|
||||||
|
{ 2,13,11},
|
||||||
|
{ 3,14,12},
|
||||||
|
{ 3,15,13},
|
||||||
|
{ 3,16,14},
|
||||||
|
{ 3,17,15},
|
||||||
|
{ 4,18,16},
|
||||||
|
{ 4,19,17},
|
||||||
|
{ 5,20,18},
|
||||||
|
{ 5,21,19},
|
||||||
|
{ 6,22,20},
|
||||||
|
{ 6,23,21},
|
||||||
|
{ 7,24,22},
|
||||||
|
{ 7,24,23},
|
||||||
|
{ 0,26, 1},
|
||||||
|
{ 1,27, 2},
|
||||||
|
{ 2,28, 4},
|
||||||
|
{ 3,29, 8},
|
||||||
|
{ 4,30,12},
|
||||||
|
{ 5,31,16},
|
||||||
|
{ 6,32,18},
|
||||||
|
{ 7,24,22}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_PEM::prepareDecomp(void) {
|
||||||
|
|
||||||
|
for (uint8 i=0; i<32; i++) {
|
||||||
|
contextInfo[i].status=0;
|
||||||
|
contextInfo[i].MPS=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
uint8 SDD1_PEM::getBit(uint8 context) {
|
||||||
|
|
||||||
|
bool8 endOfRun;
|
||||||
|
uint8 bit;
|
||||||
|
|
||||||
|
SDD1_ContextInfo *pContInfo=&contextInfo[context];
|
||||||
|
uint8 currStatus = pContInfo->status;
|
||||||
|
const state *pState=&SDD1_PEM::evolution_table[currStatus];
|
||||||
|
uint8 currentMPS=pContInfo->MPS;
|
||||||
|
|
||||||
|
bit=(BG[pState->code_num])->getBit(&endOfRun);
|
||||||
|
|
||||||
|
if (endOfRun)
|
||||||
|
if (bit) {
|
||||||
|
if (!(currStatus & 0xfe)) (pContInfo->MPS)^=0x01;
|
||||||
|
(pContInfo->status)=pState->nextIfLPS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
(pContInfo->status)=pState->nextIfMPS;
|
||||||
|
|
||||||
|
return bit^currentMPS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
|
||||||
|
PEM(associatedPEM)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_CM::prepareDecomp(uint32 first_byte) {
|
||||||
|
|
||||||
|
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||||
|
contextBitsInfo = SDD1_read(first_byte) & 0x30;
|
||||||
|
bit_number=0;
|
||||||
|
for (int i=0; i<8; i++) prevBitplaneBits[i]=0;
|
||||||
|
switch (bitplanesInfo) {
|
||||||
|
case 0x00:
|
||||||
|
currBitplane = 1;
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
currBitplane = 7;
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
currBitplane = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
uint8 SDD1_CM::getBit(void) {
|
||||||
|
|
||||||
|
uint8 currContext;
|
||||||
|
uint16 *context_bits;
|
||||||
|
|
||||||
|
switch (bitplanesInfo) {
|
||||||
|
case 0x00:
|
||||||
|
currBitplane ^= 0x01;
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
currBitplane ^= 0x01;
|
||||||
|
if (!(bit_number & 0x7f)) currBitplane = ((currBitplane+2) & 0x07);
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
currBitplane ^= 0x01;
|
||||||
|
if (!(bit_number & 0x7f)) currBitplane ^= 0x02;
|
||||||
|
break;
|
||||||
|
case 0xc0:
|
||||||
|
currBitplane = bit_number & 0x07;
|
||||||
|
}
|
||||||
|
|
||||||
|
context_bits = &prevBitplaneBits[currBitplane];
|
||||||
|
|
||||||
|
currContext=(currBitplane & 0x01)<<4;
|
||||||
|
switch (contextBitsInfo) {
|
||||||
|
case 0x00:
|
||||||
|
currContext|=((*context_bits & 0x01c0)>>5)|(*context_bits & 0x0001);
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0001);
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
currContext|=((*context_bits & 0x00c0)>>5)|(*context_bits & 0x0001);
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
currContext|=((*context_bits & 0x0180)>>5)|(*context_bits & 0x0003);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 bit=PEM->getBit(currContext);
|
||||||
|
|
||||||
|
*context_bits <<= 1;
|
||||||
|
*context_bits |= bit;
|
||||||
|
|
||||||
|
bit_number++;
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
|
||||||
|
CM(associatedCM)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_OL::prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf) {
|
||||||
|
|
||||||
|
bitplanesInfo = SDD1_read(first_byte) & 0xc0;
|
||||||
|
length=out_len;
|
||||||
|
buffer=out_buf;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1_OL::launch(void) {
|
||||||
|
|
||||||
|
uint8 i;
|
||||||
|
uint8 register1, register2;
|
||||||
|
|
||||||
|
switch (bitplanesInfo) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x40:
|
||||||
|
case 0x80:
|
||||||
|
i=1;
|
||||||
|
do { //if length==0, we output 2^16 bytes
|
||||||
|
if (!i) {
|
||||||
|
*(buffer++)=register2;
|
||||||
|
i=~i;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (register1=register2=0, i=0x80; i; i>>=1) {
|
||||||
|
if (CM->getBit()) register1 |= i;
|
||||||
|
if (CM->getBit()) register2 |= i;
|
||||||
|
}
|
||||||
|
*(buffer++)=register1;
|
||||||
|
}
|
||||||
|
} while (--length);
|
||||||
|
break;
|
||||||
|
case 0xc0:
|
||||||
|
do {
|
||||||
|
for (register1=0, i=0x01; i; i<<=1) {
|
||||||
|
if (CM->getBit()) register1 |= i;
|
||||||
|
}
|
||||||
|
*(buffer++)=register1;
|
||||||
|
} while (--length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void SDD1emu::decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf) {
|
||||||
|
|
||||||
|
IM.prepareDecomp(in_buf);
|
||||||
|
BG0.prepareDecomp();
|
||||||
|
BG1.prepareDecomp();
|
||||||
|
BG2.prepareDecomp();
|
||||||
|
BG3.prepareDecomp();
|
||||||
|
BG4.prepareDecomp();
|
||||||
|
BG5.prepareDecomp();
|
||||||
|
BG6.prepareDecomp();
|
||||||
|
BG7.prepareDecomp();
|
||||||
|
PEM.prepareDecomp();
|
||||||
|
CM.prepareDecomp(in_buf);
|
||||||
|
OL.prepareDecomp(in_buf, out_len, out_buf);
|
||||||
|
|
||||||
|
OL.launch();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
SDD1emu::SDD1emu() :
|
||||||
|
GCD(&IM),
|
||||||
|
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
|
||||||
|
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
|
||||||
|
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
|
||||||
|
CM(&PEM),
|
||||||
|
OL(&CM)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif
|
||||||
162
bsnes/chip/sdd1/sdd1emu.hpp
Executable file
162
bsnes/chip/sdd1/sdd1emu.hpp
Executable file
@ -0,0 +1,162 @@
|
|||||||
|
/************************************************************************
|
||||||
|
|
||||||
|
S-DD1'algorithm emulation code
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Author: Andreas Naive
|
||||||
|
Date: August 2003
|
||||||
|
Last update: October 2004
|
||||||
|
|
||||||
|
This code is Public Domain. There is no copyright holded by the author.
|
||||||
|
Said this, the author wish to explicitly emphasize his inalienable moral rights
|
||||||
|
over this piece of intelectual work and the previous research that made it
|
||||||
|
possible, as recognized by most of the copyright laws around the world.
|
||||||
|
|
||||||
|
This code is provided 'as-is', with no warranty, expressed or implied.
|
||||||
|
No responsability is assumed by the author in connection with it.
|
||||||
|
|
||||||
|
The author is greatly indebted with The Dumper, without whose help and
|
||||||
|
patience providing him with real S-DD1 data the research would have never been
|
||||||
|
possible. He also wish to note that in the very beggining of his research,
|
||||||
|
Neviksti had done some steps in the right direction. By last, the author is
|
||||||
|
indirectly indebted to all the people that worked and contributed in the
|
||||||
|
S-DD1 issue in the past.
|
||||||
|
|
||||||
|
An algorithm's documentation is available as a separate document.
|
||||||
|
The implementation is obvious when the algorithm is
|
||||||
|
understood.
|
||||||
|
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
typedef uint8_t bool8;
|
||||||
|
|
||||||
|
class SDD1_IM { //Input Manager
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_IM(void) {}
|
||||||
|
void prepareDecomp(uint32 in_buf);
|
||||||
|
uint8 getCodeword(const uint8 code_len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 byte_ptr;
|
||||||
|
uint8 bit_count;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_GCD { //Golomb-Code Decoder
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_GCD(SDD1_IM *associatedIM);
|
||||||
|
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDD1_IM *const IM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_BG { // Bits Generator
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||||
|
void prepareDecomp(void);
|
||||||
|
uint8 getBit(bool8 *endOfRun);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8 code_num;
|
||||||
|
uint8 MPScount;
|
||||||
|
bool8 LPSind;
|
||||||
|
SDD1_GCD *const GCD;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_PEM { //Probability Estimation Module
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||||
|
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||||
|
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||||
|
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||||
|
void prepareDecomp(void);
|
||||||
|
uint8 getBit(uint8 context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct state {
|
||||||
|
uint8 code_num;
|
||||||
|
uint8 nextIfMPS;
|
||||||
|
uint8 nextIfLPS;
|
||||||
|
};
|
||||||
|
static const state evolution_table[];
|
||||||
|
struct SDD1_ContextInfo {
|
||||||
|
uint8 status;
|
||||||
|
uint8 MPS;
|
||||||
|
} contextInfo[32];
|
||||||
|
SDD1_BG * BG[8];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_CM { //Context Model
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||||
|
void prepareDecomp(uint32 first_byte);
|
||||||
|
uint8 getBit(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 bitplanesInfo;
|
||||||
|
uint8 contextBitsInfo;
|
||||||
|
uint8 bit_number;
|
||||||
|
uint8 currBitplane;
|
||||||
|
uint16 prevBitplaneBits[8];
|
||||||
|
SDD1_PEM *const PEM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_OL { //Output Logic
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_OL(SDD1_CM *associatedCM);
|
||||||
|
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||||
|
void launch(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 bitplanesInfo;
|
||||||
|
uint16 length;
|
||||||
|
uint8 *buffer;
|
||||||
|
SDD1_CM *const CM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1emu {
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1emu(void);
|
||||||
|
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDD1_IM IM;
|
||||||
|
SDD1_GCD GCD;
|
||||||
|
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||||
|
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||||
|
SDD1_PEM PEM;
|
||||||
|
SDD1_CM CM;
|
||||||
|
SDD1_OL OL;
|
||||||
|
|
||||||
|
};
|
||||||
511
bsnes/chip/spc7110/decomp.cpp
Executable file
511
bsnes/chip/spc7110/decomp.cpp
Executable file
@ -0,0 +1,511 @@
|
|||||||
|
#ifdef SPC7110_CPP
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::read() {
|
||||||
|
if(decomp_buffer_length == 0) {
|
||||||
|
//decompress at least (decomp_buffer_size / 2) bytes to the buffer
|
||||||
|
switch(decomp_mode) {
|
||||||
|
case 0: mode0(false); break;
|
||||||
|
case 1: mode1(false); break;
|
||||||
|
case 2: mode2(false); break;
|
||||||
|
default: return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 data = decomp_buffer[decomp_buffer_rdoffset++];
|
||||||
|
decomp_buffer_rdoffset &= decomp_buffer_size - 1;
|
||||||
|
decomp_buffer_length--;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::write(uint8 data) {
|
||||||
|
decomp_buffer[decomp_buffer_wroffset++] = data;
|
||||||
|
decomp_buffer_wroffset &= decomp_buffer_size - 1;
|
||||||
|
decomp_buffer_length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::dataread() {
|
||||||
|
unsigned size = memory::cartrom.size() - 0x100000;
|
||||||
|
while(decomp_offset >= size) decomp_offset -= size;
|
||||||
|
return memory::cartrom.read(0x100000 + decomp_offset++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
||||||
|
decomp_mode = mode;
|
||||||
|
decomp_offset = offset;
|
||||||
|
|
||||||
|
decomp_buffer_rdoffset = 0;
|
||||||
|
decomp_buffer_wroffset = 0;
|
||||||
|
decomp_buffer_length = 0;
|
||||||
|
|
||||||
|
//reset context states
|
||||||
|
for(unsigned i = 0; i < 32; i++) {
|
||||||
|
context[i].index = 0;
|
||||||
|
context[i].invert = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(decomp_mode) {
|
||||||
|
case 0: mode0(true); break;
|
||||||
|
case 1: mode1(true); break;
|
||||||
|
case 2: mode2(true); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//decompress up to requested output data index
|
||||||
|
while(index--) read();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode0(bool init) {
|
||||||
|
static uint8 val, in, span;
|
||||||
|
static int out, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
out = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned bit = 0; bit < 8; bit++) {
|
||||||
|
//get context
|
||||||
|
uint8 mask = (1 << (bit & 3)) - 1;
|
||||||
|
uint8 con = mask + ((inverts & mask) ^ (lps & mask));
|
||||||
|
if(bit > 3) con += 15;
|
||||||
|
|
||||||
|
//get prob and mps
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
unsigned mps = (((out >> 15) & 1) ^ context[con].invert);
|
||||||
|
|
||||||
|
//get bit
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
out = (out << 1) + mps;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
out = (out << 1) + 1 - mps;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
inverts = (inverts << 1) + context[con].invert;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save byte
|
||||||
|
write(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode1(bool init) {
|
||||||
|
static int pixelorder[4], realorder[4];
|
||||||
|
static uint8 in, val, span;
|
||||||
|
static int out, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
for(unsigned i = 0; i < 4; i++) pixelorder[i] = i;
|
||||||
|
out = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned pixel = 0; pixel < 8; pixel++) {
|
||||||
|
//get first symbol context
|
||||||
|
unsigned a = ((out >> (1 * 2)) & 3);
|
||||||
|
unsigned b = ((out >> (7 * 2)) & 3);
|
||||||
|
unsigned c = ((out >> (8 * 2)) & 3);
|
||||||
|
unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
|
||||||
|
|
||||||
|
//update pixel order
|
||||||
|
unsigned m, n;
|
||||||
|
for(m = 0; m < 4; m++) if(pixelorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
|
||||||
|
pixelorder[0] = a;
|
||||||
|
|
||||||
|
//calculate the real pixel order
|
||||||
|
for(m = 0; m < 4; m++) realorder[m] = pixelorder[m];
|
||||||
|
|
||||||
|
//rotate reference pixel c value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == c) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = c;
|
||||||
|
|
||||||
|
//rotate reference pixel b value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == b) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = b;
|
||||||
|
|
||||||
|
//rotate reference pixel a value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = a;
|
||||||
|
|
||||||
|
//get 2 symbols
|
||||||
|
for(unsigned bit = 0; bit < 2; bit++) {
|
||||||
|
//get prob
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
|
||||||
|
//get symbol
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
inverts = (inverts << 1) + context[con].invert;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
|
||||||
|
//get next context
|
||||||
|
con = 5 + (con << 1) + ((lps ^ inverts) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get pixel
|
||||||
|
b = realorder[(lps ^ inverts) & 3];
|
||||||
|
out = (out << 2) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//turn pixel data into bitplanes
|
||||||
|
unsigned data = morton_2x8(out);
|
||||||
|
write(data >> 8);
|
||||||
|
write(data >> 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode2(bool init) {
|
||||||
|
static int pixelorder[16], realorder[16];
|
||||||
|
static uint8 bitplanebuffer[16], buffer_index;
|
||||||
|
static uint8 in, val, span;
|
||||||
|
static int out0, out1, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
for(unsigned i = 0; i < 16; i++) pixelorder[i] = i;
|
||||||
|
buffer_index = 0;
|
||||||
|
out0 = out1 = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned pixel = 0; pixel < 8; pixel++) {
|
||||||
|
//get first symbol context
|
||||||
|
unsigned a = ((out0 >> (0 * 4)) & 15);
|
||||||
|
unsigned b = ((out0 >> (7 * 4)) & 15);
|
||||||
|
unsigned c = ((out1 >> (0 * 4)) & 15);
|
||||||
|
unsigned con = 0;
|
||||||
|
unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
|
||||||
|
|
||||||
|
//update pixel order
|
||||||
|
unsigned m, n;
|
||||||
|
for(m = 0; m < 16; m++) if(pixelorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
|
||||||
|
pixelorder[0] = a;
|
||||||
|
|
||||||
|
//calculate the real pixel order
|
||||||
|
for(m = 0; m < 16; m++) realorder[m] = pixelorder[m];
|
||||||
|
|
||||||
|
//rotate reference pixel c value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == c) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = c;
|
||||||
|
|
||||||
|
//rotate reference pixel b value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == b) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = b;
|
||||||
|
|
||||||
|
//rotate reference pixel a value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = a;
|
||||||
|
|
||||||
|
//get 4 symbols
|
||||||
|
for(unsigned bit = 0; bit < 4; bit++) {
|
||||||
|
//get prob
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
|
||||||
|
//get symbol
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
unsigned invertbit = context[con].invert;
|
||||||
|
inverts = (inverts << 1) + invertbit;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
|
||||||
|
//get next context
|
||||||
|
con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get pixel
|
||||||
|
b = realorder[(lps ^ inverts) & 0x0f];
|
||||||
|
out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
|
||||||
|
out0 = (out0 << 4) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert pixel data into bitplanes
|
||||||
|
unsigned data = morton_4x8(out0);
|
||||||
|
write(data >> 24);
|
||||||
|
write(data >> 16);
|
||||||
|
bitplanebuffer[buffer_index++] = data >> 8;
|
||||||
|
bitplanebuffer[buffer_index++] = data >> 0;
|
||||||
|
|
||||||
|
if(buffer_index == 16) {
|
||||||
|
for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]);
|
||||||
|
buffer_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
const uint8 SPC7110Decomp::evolution_table[53][4] = {
|
||||||
|
//{ prob, nextlps, nextmps, toggle invert },
|
||||||
|
|
||||||
|
{ 0x5a, 1, 1, 1 },
|
||||||
|
{ 0x25, 6, 2, 0 },
|
||||||
|
{ 0x11, 8, 3, 0 },
|
||||||
|
{ 0x08, 10, 4, 0 },
|
||||||
|
{ 0x03, 12, 5, 0 },
|
||||||
|
{ 0x01, 15, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x5a, 7, 7, 1 },
|
||||||
|
{ 0x3f, 19, 8, 0 },
|
||||||
|
{ 0x2c, 21, 9, 0 },
|
||||||
|
{ 0x20, 22, 10, 0 },
|
||||||
|
{ 0x17, 23, 11, 0 },
|
||||||
|
{ 0x11, 25, 12, 0 },
|
||||||
|
{ 0x0c, 26, 13, 0 },
|
||||||
|
{ 0x09, 28, 14, 0 },
|
||||||
|
{ 0x07, 29, 15, 0 },
|
||||||
|
{ 0x05, 31, 16, 0 },
|
||||||
|
{ 0x04, 32, 17, 0 },
|
||||||
|
{ 0x03, 34, 18, 0 },
|
||||||
|
{ 0x02, 35, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x5a, 20, 20, 1 },
|
||||||
|
{ 0x48, 39, 21, 0 },
|
||||||
|
{ 0x3a, 40, 22, 0 },
|
||||||
|
{ 0x2e, 42, 23, 0 },
|
||||||
|
{ 0x26, 44, 24, 0 },
|
||||||
|
{ 0x1f, 45, 25, 0 },
|
||||||
|
{ 0x19, 46, 26, 0 },
|
||||||
|
{ 0x15, 25, 27, 0 },
|
||||||
|
{ 0x11, 26, 28, 0 },
|
||||||
|
{ 0x0e, 26, 29, 0 },
|
||||||
|
{ 0x0b, 27, 30, 0 },
|
||||||
|
{ 0x09, 28, 31, 0 },
|
||||||
|
{ 0x08, 29, 32, 0 },
|
||||||
|
{ 0x07, 30, 33, 0 },
|
||||||
|
{ 0x05, 31, 34, 0 },
|
||||||
|
{ 0x04, 33, 35, 0 },
|
||||||
|
{ 0x04, 33, 36, 0 },
|
||||||
|
{ 0x03, 34, 37, 0 },
|
||||||
|
{ 0x02, 35, 38, 0 },
|
||||||
|
{ 0x02, 36, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x58, 39, 40, 1 },
|
||||||
|
{ 0x4d, 47, 41, 0 },
|
||||||
|
{ 0x43, 48, 42, 0 },
|
||||||
|
{ 0x3b, 49, 43, 0 },
|
||||||
|
{ 0x34, 50, 44, 0 },
|
||||||
|
{ 0x2e, 51, 45, 0 },
|
||||||
|
{ 0x29, 44, 46, 0 },
|
||||||
|
{ 0x25, 45, 24, 0 },
|
||||||
|
|
||||||
|
{ 0x56, 47, 48, 1 },
|
||||||
|
{ 0x4f, 47, 49, 0 },
|
||||||
|
{ 0x47, 48, 50, 0 },
|
||||||
|
{ 0x41, 49, 51, 0 },
|
||||||
|
{ 0x3c, 50, 52, 0 },
|
||||||
|
{ 0x37, 51, 43, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8 SPC7110Decomp::mode2_context_table[32][2] = {
|
||||||
|
//{ next 0, next 1 },
|
||||||
|
|
||||||
|
{ 1, 2 },
|
||||||
|
|
||||||
|
{ 3, 8 },
|
||||||
|
{ 13, 14 },
|
||||||
|
|
||||||
|
{ 15, 16 },
|
||||||
|
{ 17, 18 },
|
||||||
|
{ 19, 20 },
|
||||||
|
{ 21, 22 },
|
||||||
|
{ 23, 24 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 27, 28 },
|
||||||
|
{ 29, 30 },
|
||||||
|
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
|
||||||
|
{ 31, 31 },
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; }
|
||||||
|
uint8 SPC7110Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; }
|
||||||
|
uint8 SPC7110Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; }
|
||||||
|
bool SPC7110Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; }
|
||||||
|
|
||||||
|
unsigned SPC7110Decomp::morton_2x8(unsigned data) {
|
||||||
|
//reverse morton lookup: de-interleave two 8-bit values
|
||||||
|
//15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8
|
||||||
|
//14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0
|
||||||
|
return morton16[0][(data >> 0) & 255] + morton16[1][(data >> 8) & 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110Decomp::morton_4x8(unsigned data) {
|
||||||
|
//reverse morton lookup: de-interleave four 8-bit values
|
||||||
|
//31, 27, 23, 19, 15, 11, 7, 3 -> 31-24
|
||||||
|
//30, 26, 22, 18, 14, 10, 6, 2 -> 23-16
|
||||||
|
//29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8
|
||||||
|
//28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0
|
||||||
|
return morton32[0][(data >> 0) & 255] + morton32[1][(data >> 8) & 255]
|
||||||
|
+ morton32[2][(data >> 16) & 255] + morton32[3][(data >> 24) & 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SPC7110Decomp::reset() {
|
||||||
|
//mode 3 is invalid; this is treated as a special case to always return 0x00
|
||||||
|
//set to mode 3 so that reading decomp port before starting first decomp will return 0x00
|
||||||
|
decomp_mode = 3;
|
||||||
|
|
||||||
|
decomp_buffer_rdoffset = 0;
|
||||||
|
decomp_buffer_wroffset = 0;
|
||||||
|
decomp_buffer_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110Decomp::SPC7110Decomp() {
|
||||||
|
decomp_buffer = new uint8_t[decomp_buffer_size];
|
||||||
|
reset();
|
||||||
|
|
||||||
|
//initialize reverse morton lookup tables
|
||||||
|
for(unsigned i = 0; i < 256; i++) {
|
||||||
|
#define map(x, y) (((i >> x) & 1) << y)
|
||||||
|
//2x8-bit
|
||||||
|
morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6)
|
||||||
|
+ map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
|
||||||
|
morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2)
|
||||||
|
+ map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
|
||||||
|
//4x8-bit
|
||||||
|
morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7)
|
||||||
|
+ map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
|
||||||
|
morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5)
|
||||||
|
+ map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
|
||||||
|
morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3)
|
||||||
|
+ map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
|
||||||
|
morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1)
|
||||||
|
+ map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
|
||||||
|
#undef map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110Decomp::~SPC7110Decomp() {
|
||||||
|
delete[] decomp_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
45
bsnes/chip/spc7110/decomp.hpp
Executable file
45
bsnes/chip/spc7110/decomp.hpp
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
class SPC7110Decomp {
|
||||||
|
public:
|
||||||
|
uint8 read();
|
||||||
|
void init(unsigned mode, unsigned offset, unsigned index);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
SPC7110Decomp();
|
||||||
|
~SPC7110Decomp();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned decomp_mode;
|
||||||
|
unsigned decomp_offset;
|
||||||
|
|
||||||
|
//read() will spool chunks half the size of decomp_buffer_size
|
||||||
|
enum { decomp_buffer_size = 64 }; //must be >= 64, and must be a power of two
|
||||||
|
uint8 *decomp_buffer;
|
||||||
|
unsigned decomp_buffer_rdoffset;
|
||||||
|
unsigned decomp_buffer_wroffset;
|
||||||
|
unsigned decomp_buffer_length;
|
||||||
|
|
||||||
|
void write(uint8 data);
|
||||||
|
uint8 dataread();
|
||||||
|
|
||||||
|
void mode0(bool init);
|
||||||
|
void mode1(bool init);
|
||||||
|
void mode2(bool init);
|
||||||
|
|
||||||
|
static const uint8 evolution_table[53][4];
|
||||||
|
static const uint8 mode2_context_table[32][2];
|
||||||
|
|
||||||
|
struct ContextState {
|
||||||
|
uint8 index;
|
||||||
|
uint8 invert;
|
||||||
|
} context[32];
|
||||||
|
|
||||||
|
uint8 probability(unsigned n);
|
||||||
|
uint8 next_lps(unsigned n);
|
||||||
|
uint8 next_mps(unsigned n);
|
||||||
|
bool toggle_invert(unsigned n);
|
||||||
|
|
||||||
|
unsigned morton16[2][256];
|
||||||
|
unsigned morton32[4][256];
|
||||||
|
unsigned morton_2x8(unsigned data);
|
||||||
|
unsigned morton_4x8(unsigned data);
|
||||||
|
};
|
||||||
672
bsnes/chip/spc7110/spc7110.cpp
Executable file
672
bsnes/chip/spc7110/spc7110.cpp
Executable file
@ -0,0 +1,672 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#define SPC7110_CPP
|
||||||
|
|
||||||
|
#include "spc7110.hpp"
|
||||||
|
#include "decomp.cpp"
|
||||||
|
|
||||||
|
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
void SPC7110::init() {}
|
||||||
|
|
||||||
|
void SPC7110::enable() {
|
||||||
|
uint16_t limit = (cartridge.has_spc7110rtc() ? 0x4842 : 0x483f);
|
||||||
|
for(uint16_t i = 0x4800; i <= limit; i++) memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::reset() {
|
||||||
|
r4801 = 0x00;
|
||||||
|
r4802 = 0x00;
|
||||||
|
r4803 = 0x00;
|
||||||
|
r4804 = 0x00;
|
||||||
|
r4805 = 0x00;
|
||||||
|
r4806 = 0x00;
|
||||||
|
r4807 = 0x00;
|
||||||
|
r4808 = 0x00;
|
||||||
|
r4809 = 0x00;
|
||||||
|
r480a = 0x00;
|
||||||
|
r480b = 0x00;
|
||||||
|
r480c = 0x00;
|
||||||
|
|
||||||
|
decomp.reset();
|
||||||
|
|
||||||
|
r4811 = 0x00;
|
||||||
|
r4812 = 0x00;
|
||||||
|
r4813 = 0x00;
|
||||||
|
r4814 = 0x00;
|
||||||
|
r4815 = 0x00;
|
||||||
|
r4816 = 0x00;
|
||||||
|
r4817 = 0x00;
|
||||||
|
r4818 = 0x00;
|
||||||
|
|
||||||
|
r481x = 0x00;
|
||||||
|
r4814_latch = false;
|
||||||
|
r4815_latch = false;
|
||||||
|
|
||||||
|
r4820 = 0x00;
|
||||||
|
r4821 = 0x00;
|
||||||
|
r4822 = 0x00;
|
||||||
|
r4823 = 0x00;
|
||||||
|
r4824 = 0x00;
|
||||||
|
r4825 = 0x00;
|
||||||
|
r4826 = 0x00;
|
||||||
|
r4827 = 0x00;
|
||||||
|
r4828 = 0x00;
|
||||||
|
r4829 = 0x00;
|
||||||
|
r482a = 0x00;
|
||||||
|
r482b = 0x00;
|
||||||
|
r482c = 0x00;
|
||||||
|
r482d = 0x00;
|
||||||
|
r482e = 0x00;
|
||||||
|
r482f = 0x00;
|
||||||
|
|
||||||
|
r4830 = 0x00;
|
||||||
|
mmio_write(0x4831, 0);
|
||||||
|
mmio_write(0x4832, 1);
|
||||||
|
mmio_write(0x4833, 2);
|
||||||
|
r4834 = 0x00;
|
||||||
|
|
||||||
|
r4840 = 0x00;
|
||||||
|
r4841 = 0x00;
|
||||||
|
r4842 = 0x00;
|
||||||
|
|
||||||
|
if(cartridge.has_spc7110rtc()) {
|
||||||
|
rtc_state = RTCS_Inactive;
|
||||||
|
rtc_mode = RTCM_Linear;
|
||||||
|
rtc_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110::datarom_addr(unsigned addr) {
|
||||||
|
unsigned size = memory::cartrom.size() - 0x100000;
|
||||||
|
while(addr >= size) addr -= size;
|
||||||
|
return addr + 0x100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
|
||||||
|
unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); }
|
||||||
|
unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); }
|
||||||
|
void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
|
||||||
|
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
|
||||||
|
|
||||||
|
void SPC7110::update_time(int offset) {
|
||||||
|
time_t rtc_time
|
||||||
|
= (memory::cartrtc.read(16) << 0)
|
||||||
|
| (memory::cartrtc.read(17) << 8)
|
||||||
|
| (memory::cartrtc.read(18) << 16)
|
||||||
|
| (memory::cartrtc.read(19) << 24);
|
||||||
|
time_t current_time = time(0) - offset;
|
||||||
|
|
||||||
|
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||||
|
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||||
|
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||||
|
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||||
|
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||||
|
//or whether time_t is signed or unsigned.
|
||||||
|
time_t diff
|
||||||
|
= (current_time >= rtc_time)
|
||||||
|
? (current_time - rtc_time)
|
||||||
|
: (std::numeric_limits<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
|
||||||
|
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||||
|
|
||||||
|
bool update = true;
|
||||||
|
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
|
||||||
|
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
|
||||||
|
|
||||||
|
if(diff > 0 && update == true) {
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||||
|
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
|
||||||
|
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
|
||||||
|
unsigned weekday = memory::cartrtc.read(12);
|
||||||
|
|
||||||
|
day--;
|
||||||
|
month--;
|
||||||
|
year += (year >= 90) ? 1900 : 2000; //range = 1990-2089
|
||||||
|
|
||||||
|
second += diff;
|
||||||
|
while(second >= 60) {
|
||||||
|
second -= 60;
|
||||||
|
|
||||||
|
minute++;
|
||||||
|
if(minute < 60) continue;
|
||||||
|
minute = 0;
|
||||||
|
|
||||||
|
hour++;
|
||||||
|
if(hour < 24) continue;
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
day++;
|
||||||
|
weekday = (weekday + 1) % 7;
|
||||||
|
unsigned days = months[month % 12];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((year % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
if(day < days) continue;
|
||||||
|
day = 0;
|
||||||
|
|
||||||
|
month++;
|
||||||
|
if(month < 12) continue;
|
||||||
|
month = 0;
|
||||||
|
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
day++;
|
||||||
|
month++;
|
||||||
|
year %= 100;
|
||||||
|
|
||||||
|
memory::cartrtc.write( 0, second % 10);
|
||||||
|
memory::cartrtc.write( 1, second / 10);
|
||||||
|
memory::cartrtc.write( 2, minute % 10);
|
||||||
|
memory::cartrtc.write( 3, minute / 10);
|
||||||
|
memory::cartrtc.write( 4, hour % 10);
|
||||||
|
memory::cartrtc.write( 5, hour / 10);
|
||||||
|
memory::cartrtc.write( 6, day % 10);
|
||||||
|
memory::cartrtc.write( 7, day / 10);
|
||||||
|
memory::cartrtc.write( 8, month % 10);
|
||||||
|
memory::cartrtc.write( 9, month / 10);
|
||||||
|
memory::cartrtc.write(10, year % 10);
|
||||||
|
memory::cartrtc.write(11, (year / 10) % 10);
|
||||||
|
memory::cartrtc.write(12, weekday % 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(16, current_time >> 0);
|
||||||
|
memory::cartrtc.write(17, current_time >> 8);
|
||||||
|
memory::cartrtc.write(18, current_time >> 16);
|
||||||
|
memory::cartrtc.write(19, current_time >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case 0x4800: {
|
||||||
|
uint16 counter = (r4809 + (r480a << 8));
|
||||||
|
counter--;
|
||||||
|
r4809 = counter;
|
||||||
|
r480a = counter >> 8;
|
||||||
|
return decomp.read();
|
||||||
|
}
|
||||||
|
case 0x4801: return r4801;
|
||||||
|
case 0x4802: return r4802;
|
||||||
|
case 0x4803: return r4803;
|
||||||
|
case 0x4804: return r4804;
|
||||||
|
case 0x4805: return r4805;
|
||||||
|
case 0x4806: return r4806;
|
||||||
|
case 0x4807: return r4807;
|
||||||
|
case 0x4808: return r4808;
|
||||||
|
case 0x4809: return r4809;
|
||||||
|
case 0x480a: return r480a;
|
||||||
|
case 0x480b: return r480b;
|
||||||
|
case 0x480c: {
|
||||||
|
uint8 status = r480c;
|
||||||
|
r480c &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
|
||||||
|
case 0x4810: {
|
||||||
|
if(r481x != 0x07) return 0x00;
|
||||||
|
|
||||||
|
unsigned addr = data_pointer();
|
||||||
|
unsigned adjust = data_adjust();
|
||||||
|
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||||
|
|
||||||
|
unsigned adjustaddr = addr;
|
||||||
|
if(r4818 & 2) {
|
||||||
|
adjustaddr += adjust;
|
||||||
|
set_data_adjust(adjust + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
|
||||||
|
if(!(r4818 & 2)) {
|
||||||
|
unsigned increment = (r4818 & 1) ? data_increment() : 1;
|
||||||
|
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
|
||||||
|
|
||||||
|
if((r4818 & 16) == 0) {
|
||||||
|
set_data_pointer(addr + increment);
|
||||||
|
} else {
|
||||||
|
set_data_adjust(adjust + increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
case 0x4811: return r4811;
|
||||||
|
case 0x4812: return r4812;
|
||||||
|
case 0x4813: return r4813;
|
||||||
|
case 0x4814: return r4814;
|
||||||
|
case 0x4815: return r4815;
|
||||||
|
case 0x4816: return r4816;
|
||||||
|
case 0x4817: return r4817;
|
||||||
|
case 0x4818: return r4818;
|
||||||
|
case 0x481a: {
|
||||||
|
if(r481x != 0x07) return 0x00;
|
||||||
|
|
||||||
|
unsigned addr = data_pointer();
|
||||||
|
unsigned adjust = data_adjust();
|
||||||
|
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||||
|
|
||||||
|
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
|
||||||
|
if((r4818 & 0x60) == 0x60) {
|
||||||
|
if((r4818 & 16) == 0) {
|
||||||
|
set_data_pointer(addr + adjust);
|
||||||
|
} else {
|
||||||
|
set_data_adjust(adjust + adjust);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
|
||||||
|
case 0x4820: return r4820;
|
||||||
|
case 0x4821: return r4821;
|
||||||
|
case 0x4822: return r4822;
|
||||||
|
case 0x4823: return r4823;
|
||||||
|
case 0x4824: return r4824;
|
||||||
|
case 0x4825: return r4825;
|
||||||
|
case 0x4826: return r4826;
|
||||||
|
case 0x4827: return r4827;
|
||||||
|
case 0x4828: return r4828;
|
||||||
|
case 0x4829: return r4829;
|
||||||
|
case 0x482a: return r482a;
|
||||||
|
case 0x482b: return r482b;
|
||||||
|
case 0x482c: return r482c;
|
||||||
|
case 0x482d: return r482d;
|
||||||
|
case 0x482e: return r482e;
|
||||||
|
case 0x482f: {
|
||||||
|
uint8 status = r482f;
|
||||||
|
r482f &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
|
||||||
|
case 0x4830: return r4830;
|
||||||
|
case 0x4831: return r4831;
|
||||||
|
case 0x4832: return r4832;
|
||||||
|
case 0x4833: return r4833;
|
||||||
|
case 0x4834: return r4834;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
|
||||||
|
case 0x4840: return r4840;
|
||||||
|
case 0x4841: {
|
||||||
|
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
|
||||||
|
|
||||||
|
r4842 = 0x80;
|
||||||
|
uint8 data = memory::cartrtc.read(rtc_index);
|
||||||
|
rtc_index = (rtc_index + 1) & 15;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
case 0x4842: {
|
||||||
|
uint8 status = r4842;
|
||||||
|
r4842 &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case 0x4801: r4801 = data; break;
|
||||||
|
case 0x4802: r4802 = data; break;
|
||||||
|
case 0x4803: r4803 = data; break;
|
||||||
|
case 0x4804: r4804 = data; break;
|
||||||
|
case 0x4805: r4805 = data; break;
|
||||||
|
case 0x4806: {
|
||||||
|
r4806 = data;
|
||||||
|
|
||||||
|
unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16));
|
||||||
|
unsigned index = (r4804 << 2);
|
||||||
|
unsigned length = (r4809 + (r480a << 8));
|
||||||
|
unsigned addr = datarom_addr(table + index);
|
||||||
|
unsigned mode = (memory::cartrom.read(addr + 0));
|
||||||
|
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
|
||||||
|
+ (memory::cartrom.read(addr + 2) << 8)
|
||||||
|
+ (memory::cartrom.read(addr + 3) << 0);
|
||||||
|
|
||||||
|
decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode);
|
||||||
|
r480c = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4807: r4807 = data; break;
|
||||||
|
case 0x4808: r4808 = data; break;
|
||||||
|
case 0x4809: r4809 = data; break;
|
||||||
|
case 0x480a: r480a = data; break;
|
||||||
|
case 0x480b: r480b = data; break;
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
|
||||||
|
case 0x4811: r4811 = data; r481x |= 0x01; break;
|
||||||
|
case 0x4812: r4812 = data; r481x |= 0x02; break;
|
||||||
|
case 0x4813: r4813 = data; r481x |= 0x04; break;
|
||||||
|
case 0x4814: {
|
||||||
|
r4814 = data;
|
||||||
|
r4814_latch = true;
|
||||||
|
if(!r4815_latch) break;
|
||||||
|
if(!(r4818 & 2)) break;
|
||||||
|
if(r4818 & 0x10) break;
|
||||||
|
|
||||||
|
if((r4818 & 0x60) == 0x20) {
|
||||||
|
unsigned increment = data_adjust() & 0xff;
|
||||||
|
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
} else if((r4818 & 0x60) == 0x40) {
|
||||||
|
unsigned increment = data_adjust();
|
||||||
|
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case 0x4815: {
|
||||||
|
r4815 = data;
|
||||||
|
r4815_latch = true;
|
||||||
|
if(!r4814_latch) break;
|
||||||
|
if(!(r4818 & 2)) break;
|
||||||
|
if(r4818 & 0x10) break;
|
||||||
|
|
||||||
|
if((r4818 & 0x60) == 0x20) {
|
||||||
|
unsigned increment = data_adjust() & 0xff;
|
||||||
|
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
} else if((r4818 & 0x60) == 0x40) {
|
||||||
|
unsigned increment = data_adjust();
|
||||||
|
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case 0x4816: r4816 = data; break;
|
||||||
|
case 0x4817: r4817 = data; break;
|
||||||
|
case 0x4818: {
|
||||||
|
if(r481x != 0x07) break;
|
||||||
|
|
||||||
|
r4818 = data;
|
||||||
|
r4814_latch = r4815_latch = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
|
||||||
|
case 0x4820: r4820 = data; break;
|
||||||
|
case 0x4821: r4821 = data; break;
|
||||||
|
case 0x4822: r4822 = data; break;
|
||||||
|
case 0x4823: r4823 = data; break;
|
||||||
|
case 0x4824: r4824 = data; break;
|
||||||
|
case 0x4825: {
|
||||||
|
r4825 = data;
|
||||||
|
|
||||||
|
if(r482e & 1) {
|
||||||
|
//signed 16-bit x 16-bit multiplication
|
||||||
|
int16 r0 = (int16)(r4824 + (r4825 << 8));
|
||||||
|
int16 r1 = (int16)(r4820 + (r4821 << 8));
|
||||||
|
|
||||||
|
signed result = r0 * r1;
|
||||||
|
r4828 = result;
|
||||||
|
r4829 = result >> 8;
|
||||||
|
r482a = result >> 16;
|
||||||
|
r482b = result >> 24;
|
||||||
|
} else {
|
||||||
|
//unsigned 16-bit x 16-bit multiplication
|
||||||
|
uint16 r0 = (uint16)(r4824 + (r4825 << 8));
|
||||||
|
uint16 r1 = (uint16)(r4820 + (r4821 << 8));
|
||||||
|
|
||||||
|
unsigned result = r0 * r1;
|
||||||
|
r4828 = result;
|
||||||
|
r4829 = result >> 8;
|
||||||
|
r482a = result >> 16;
|
||||||
|
r482b = result >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
r482f = 0x80;
|
||||||
|
} break;
|
||||||
|
case 0x4826: r4826 = data; break;
|
||||||
|
case 0x4827: {
|
||||||
|
r4827 = data;
|
||||||
|
|
||||||
|
if(r482e & 1) {
|
||||||
|
//signed 32-bit x 16-bit division
|
||||||
|
int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||||
|
int16 divisor = (int16)(r4826 + (r4827 << 8));
|
||||||
|
|
||||||
|
int32 quotient;
|
||||||
|
int16 remainder;
|
||||||
|
|
||||||
|
if(divisor) {
|
||||||
|
quotient = (int32)(dividend / divisor);
|
||||||
|
remainder = (int32)(dividend % divisor);
|
||||||
|
} else {
|
||||||
|
//illegal division by zero
|
||||||
|
quotient = 0;
|
||||||
|
remainder = dividend & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
r4828 = quotient;
|
||||||
|
r4829 = quotient >> 8;
|
||||||
|
r482a = quotient >> 16;
|
||||||
|
r482b = quotient >> 24;
|
||||||
|
|
||||||
|
r482c = remainder;
|
||||||
|
r482d = remainder >> 8;
|
||||||
|
} else {
|
||||||
|
//unsigned 32-bit x 16-bit division
|
||||||
|
uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||||
|
uint16 divisor = (uint16)(r4826 + (r4827 << 8));
|
||||||
|
|
||||||
|
uint32 quotient;
|
||||||
|
uint16 remainder;
|
||||||
|
|
||||||
|
if(divisor) {
|
||||||
|
quotient = (uint32)(dividend / divisor);
|
||||||
|
remainder = (uint16)(dividend % divisor);
|
||||||
|
} else {
|
||||||
|
//illegal division by zero
|
||||||
|
quotient = 0;
|
||||||
|
remainder = dividend & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
r4828 = quotient;
|
||||||
|
r4829 = quotient >> 8;
|
||||||
|
r482a = quotient >> 16;
|
||||||
|
r482b = quotient >> 24;
|
||||||
|
|
||||||
|
r482c = remainder;
|
||||||
|
r482d = remainder >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r482f = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x482e: {
|
||||||
|
//reset math unit
|
||||||
|
r4820 = r4821 = r4822 = r4823 = 0;
|
||||||
|
r4824 = r4825 = r4826 = r4827 = 0;
|
||||||
|
r4828 = r4829 = r482a = r482b = 0;
|
||||||
|
r482c = r482d = 0;
|
||||||
|
|
||||||
|
r482e = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
|
||||||
|
case 0x4830: r4830 = data; break;
|
||||||
|
|
||||||
|
case 0x4831: {
|
||||||
|
r4831 = data;
|
||||||
|
dx_offset = datarom_addr((data & 7) * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4832: {
|
||||||
|
r4832 = data;
|
||||||
|
ex_offset = datarom_addr((data & 7) * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4833: {
|
||||||
|
r4833 = data;
|
||||||
|
fx_offset = datarom_addr((data & 7) * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4834: r4834 = data; break;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
|
||||||
|
case 0x4840: {
|
||||||
|
r4840 = data;
|
||||||
|
if(!(r4840 & 1)) {
|
||||||
|
//disable RTC
|
||||||
|
rtc_state = RTCS_Inactive;
|
||||||
|
update_time();
|
||||||
|
} else {
|
||||||
|
//enable RTC
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_state = RTCS_ModeSelect;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4841: {
|
||||||
|
r4841 = data;
|
||||||
|
|
||||||
|
switch(rtc_state) {
|
||||||
|
case RTCS_ModeSelect: {
|
||||||
|
if(data == RTCM_Linear || data == RTCM_Indexed) {
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_state = RTCS_IndexSelect;
|
||||||
|
rtc_mode = (RTC_Mode)data;
|
||||||
|
rtc_index = 0;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RTCS_IndexSelect: {
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_index = data & 15;
|
||||||
|
if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RTCS_Write: {
|
||||||
|
r4842 = 0x80;
|
||||||
|
|
||||||
|
//control register 0
|
||||||
|
if(rtc_index == 13) {
|
||||||
|
//increment second counter
|
||||||
|
if(data & 2) update_time(+1);
|
||||||
|
|
||||||
|
//round minute counter
|
||||||
|
if(data & 8) {
|
||||||
|
update_time();
|
||||||
|
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
//clear seconds
|
||||||
|
memory::cartrtc.write(0, 0);
|
||||||
|
memory::cartrtc.write(1, 0);
|
||||||
|
|
||||||
|
if(second >= 30) update_time(+60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//control register 2
|
||||||
|
if(rtc_index == 15) {
|
||||||
|
//disable timer and clear second counter
|
||||||
|
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
|
||||||
|
update_time();
|
||||||
|
|
||||||
|
//clear seconds
|
||||||
|
memory::cartrtc.write(0, 0);
|
||||||
|
memory::cartrtc.write(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//disable timer
|
||||||
|
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
|
||||||
|
update_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(rtc_index, data & 15);
|
||||||
|
rtc_index = (rtc_index + 1) & 15;
|
||||||
|
} break;
|
||||||
|
} //switch(rtc_state)
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110::read(unsigned addr) {
|
||||||
|
//$[00-0f|80-8f]:[8000-ffff], $[c0-cf]:[0000-ffff] mapped directly to memory::cartrom
|
||||||
|
|
||||||
|
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
||||||
|
//$[00|30]:[6000-7fff]
|
||||||
|
return memory::cartram.read(addr & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xff0000) == 0x500000) {
|
||||||
|
//$[50]:[0000-ffff]
|
||||||
|
return mmio_read(0x4800);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf00000) == 0xd00000) {
|
||||||
|
//$[d0-df]:[0000-ffff]
|
||||||
|
return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf00000) == 0xe00000) {
|
||||||
|
//$[e0-ef]:[0000-ffff]
|
||||||
|
return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf00000) == 0xf00000) {
|
||||||
|
//$[f0-ff]:[0000-ffff]
|
||||||
|
return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::write(unsigned addr, uint8 data) {
|
||||||
|
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
||||||
|
//$[00|30]:[6000-7fff]
|
||||||
|
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110::SPC7110() {
|
||||||
|
}
|
||||||
133
bsnes/chip/spc7110/spc7110.hpp
Executable file
133
bsnes/chip/spc7110/spc7110.hpp
Executable file
@ -0,0 +1,133 @@
|
|||||||
|
/*****
|
||||||
|
* SPC7110 emulator - version 0.03 (2008-08-10)
|
||||||
|
* Copyright (c) 2008, byuu and neviksti
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* The software is provided "as is" and the author disclaims all warranties
|
||||||
|
* with regard to this software including all implied warranties of
|
||||||
|
* merchantibility and fitness, in no event shall the author be liable for
|
||||||
|
* any special, direct, indirect, or consequential damages or any damages
|
||||||
|
* whatsoever resulting from loss of use, data or profits, whether in an
|
||||||
|
* action of contract, negligence or other tortious action, arising out of
|
||||||
|
* or in connection with the use or performance of this software.
|
||||||
|
*****/
|
||||||
|
|
||||||
|
#include "decomp.hpp"
|
||||||
|
|
||||||
|
class SPC7110 : public MMIO, public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
unsigned datarom_addr(unsigned addr);
|
||||||
|
|
||||||
|
unsigned data_pointer();
|
||||||
|
unsigned data_adjust();
|
||||||
|
unsigned data_increment();
|
||||||
|
void set_data_pointer(unsigned addr);
|
||||||
|
void set_data_adjust(unsigned addr);
|
||||||
|
|
||||||
|
void update_time(int offset = 0);
|
||||||
|
time_t create_time();
|
||||||
|
|
||||||
|
uint8 mmio_read (unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
//spc7110decomp
|
||||||
|
void decomp_init();
|
||||||
|
uint8 decomp_read();
|
||||||
|
|
||||||
|
SPC7110();
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
uint8 r4801; //compression table low
|
||||||
|
uint8 r4802; //compression table high
|
||||||
|
uint8 r4803; //compression table bank
|
||||||
|
uint8 r4804; //compression table index
|
||||||
|
uint8 r4805; //decompression buffer index low
|
||||||
|
uint8 r4806; //decompression buffer index high
|
||||||
|
uint8 r4807; //???
|
||||||
|
uint8 r4808; //???
|
||||||
|
uint8 r4809; //compression length low
|
||||||
|
uint8 r480a; //compression length high
|
||||||
|
uint8 r480b; //decompression control register
|
||||||
|
uint8 r480c; //decompression status
|
||||||
|
|
||||||
|
SPC7110Decomp decomp;
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
uint8 r4811; //data pointer low
|
||||||
|
uint8 r4812; //data pointer high
|
||||||
|
uint8 r4813; //data pointer bank
|
||||||
|
uint8 r4814; //data adjust low
|
||||||
|
uint8 r4815; //data adjust high
|
||||||
|
uint8 r4816; //data increment low
|
||||||
|
uint8 r4817; //data increment high
|
||||||
|
uint8 r4818; //data port control register
|
||||||
|
|
||||||
|
uint8 r481x;
|
||||||
|
|
||||||
|
bool r4814_latch;
|
||||||
|
bool r4815_latch;
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0
|
||||||
|
uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1
|
||||||
|
uint8 r4822; //32-bit dividend B2
|
||||||
|
uint8 r4823; //32-bit dividend B3
|
||||||
|
uint8 r4824; //16-bit multiplier B0
|
||||||
|
uint8 r4825; //16-bit multiplier B1
|
||||||
|
uint8 r4826; //16-bit divisor B0
|
||||||
|
uint8 r4827; //16-bit divisor B1
|
||||||
|
uint8 r4828; //32-bit product B0, 32-bit quotient B0
|
||||||
|
uint8 r4829; //32-bit product B1, 32-bit quotient B1
|
||||||
|
uint8 r482a; //32-bit product B2, 32-bit quotient B2
|
||||||
|
uint8 r482b; //32-bit product B3, 32-bit quotient B3
|
||||||
|
uint8 r482c; //16-bit remainder B0
|
||||||
|
uint8 r482d; //16-bit remainder B1
|
||||||
|
uint8 r482e; //math control register
|
||||||
|
uint8 r482f; //math status
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
uint8 r4830; //SRAM write enable
|
||||||
|
uint8 r4831; //$[d0-df]:[0000-ffff] mapping
|
||||||
|
uint8 r4832; //$[e0-ef]:[0000-ffff] mapping
|
||||||
|
uint8 r4833; //$[f0-ff]:[0000-ffff] mapping
|
||||||
|
uint8 r4834; //???
|
||||||
|
|
||||||
|
unsigned dx_offset;
|
||||||
|
unsigned ex_offset;
|
||||||
|
unsigned fx_offset;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
uint8 r4840; //RTC latch
|
||||||
|
uint8 r4841; //RTC index/data port
|
||||||
|
uint8 r4842; //RTC status
|
||||||
|
|
||||||
|
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write } rtc_state;
|
||||||
|
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c } rtc_mode;
|
||||||
|
unsigned rtc_index;
|
||||||
|
|
||||||
|
static const unsigned months[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SPC7110 spc7110;
|
||||||
226
bsnes/chip/srtc/srtc.cpp
Executable file
226
bsnes/chip/srtc/srtc.cpp
Executable file
@ -0,0 +1,226 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#include <../cart/cart.hpp>
|
||||||
|
#include "srtc.hpp"
|
||||||
|
|
||||||
|
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
void SRTC::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::enable() {
|
||||||
|
memory::mmio.map(0x2800, *this);
|
||||||
|
memory::mmio.map(0x2801, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::reset() {
|
||||||
|
rtc_mode = RTCM_Read;
|
||||||
|
rtc_index = -1;
|
||||||
|
update_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::update_time() {
|
||||||
|
time_t rtc_time
|
||||||
|
= (memory::cartrtc.read(16) << 0)
|
||||||
|
| (memory::cartrtc.read(17) << 8)
|
||||||
|
| (memory::cartrtc.read(18) << 16)
|
||||||
|
| (memory::cartrtc.read(19) << 24);
|
||||||
|
time_t current_time = time(0);
|
||||||
|
|
||||||
|
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||||
|
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||||
|
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||||
|
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||||
|
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||||
|
//or whether time_t is signed or unsigned.
|
||||||
|
time_t diff
|
||||||
|
= (current_time >= rtc_time)
|
||||||
|
? (current_time - rtc_time)
|
||||||
|
: (std::numeric_limits<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
|
||||||
|
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||||
|
|
||||||
|
if(diff > 0) {
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||||
|
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8);
|
||||||
|
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||||
|
unsigned weekday = memory::cartrtc.read(12);
|
||||||
|
|
||||||
|
day--;
|
||||||
|
month--;
|
||||||
|
year += 1000;
|
||||||
|
|
||||||
|
second += diff;
|
||||||
|
while(second >= 60) {
|
||||||
|
second -= 60;
|
||||||
|
|
||||||
|
minute++;
|
||||||
|
if(minute < 60) continue;
|
||||||
|
minute = 0;
|
||||||
|
|
||||||
|
hour++;
|
||||||
|
if(hour < 24) continue;
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
day++;
|
||||||
|
weekday = (weekday + 1) % 7;
|
||||||
|
unsigned days = months[month % 12];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((year % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
if(day < days) continue;
|
||||||
|
day = 0;
|
||||||
|
|
||||||
|
month++;
|
||||||
|
if(month < 12) continue;
|
||||||
|
month = 0;
|
||||||
|
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
day++;
|
||||||
|
month++;
|
||||||
|
year -= 1000;
|
||||||
|
|
||||||
|
memory::cartrtc.write( 0, second % 10);
|
||||||
|
memory::cartrtc.write( 1, second / 10);
|
||||||
|
memory::cartrtc.write( 2, minute % 10);
|
||||||
|
memory::cartrtc.write( 3, minute / 10);
|
||||||
|
memory::cartrtc.write( 4, hour % 10);
|
||||||
|
memory::cartrtc.write( 5, hour / 10);
|
||||||
|
memory::cartrtc.write( 6, day % 10);
|
||||||
|
memory::cartrtc.write( 7, day / 10);
|
||||||
|
memory::cartrtc.write( 8, month);
|
||||||
|
memory::cartrtc.write( 9, year % 10);
|
||||||
|
memory::cartrtc.write(10, (year / 10) % 10);
|
||||||
|
memory::cartrtc.write(11, year / 100);
|
||||||
|
memory::cartrtc.write(12, weekday % 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(16, current_time >> 0);
|
||||||
|
memory::cartrtc.write(17, current_time >> 8);
|
||||||
|
memory::cartrtc.write(18, current_time >> 16);
|
||||||
|
memory::cartrtc.write(19, current_time >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns day of week for specified date
|
||||||
|
//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday
|
||||||
|
//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008
|
||||||
|
unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
|
||||||
|
unsigned y = 1900, m = 1; //epoch is 1900-01-01
|
||||||
|
unsigned sum = 0; //number of days passed since epoch
|
||||||
|
|
||||||
|
year = max(1900, year);
|
||||||
|
month = max(1, min(12, month));
|
||||||
|
day = max(1, min(31, day));
|
||||||
|
|
||||||
|
while(y < year) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((y % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
sum += leapyear ? 366 : 365;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(m < month) {
|
||||||
|
unsigned days = months[m - 1];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((y % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
sum += days;
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += day - 1;
|
||||||
|
return (sum + 1) % 7; //1900-01-01 was a Monday
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SRTC::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2800) {
|
||||||
|
if(rtc_mode != RTCM_Read) return 0x00;
|
||||||
|
|
||||||
|
if(rtc_index < 0) {
|
||||||
|
update_time();
|
||||||
|
rtc_index++;
|
||||||
|
return 0x0f;
|
||||||
|
} else if(rtc_index > 12) {
|
||||||
|
rtc_index = -1;
|
||||||
|
return 0x0f;
|
||||||
|
} else {
|
||||||
|
return memory::cartrtc.read(rtc_index++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2801) {
|
||||||
|
data &= 0x0f; //only the low four bits are used
|
||||||
|
|
||||||
|
if(data == 0x0d) {
|
||||||
|
rtc_mode = RTCM_Read;
|
||||||
|
rtc_index = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data == 0x0e) {
|
||||||
|
rtc_mode = RTCM_Command;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data == 0x0f) return; //unknown behavior
|
||||||
|
|
||||||
|
if(rtc_mode == RTCM_Write) {
|
||||||
|
if(rtc_index >= 0 && rtc_index < 12) {
|
||||||
|
memory::cartrtc.write(rtc_index++, data);
|
||||||
|
|
||||||
|
if(rtc_index == 12) {
|
||||||
|
//day of week is automatically calculated and written
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8);
|
||||||
|
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||||
|
year += 1000;
|
||||||
|
|
||||||
|
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(rtc_mode == RTCM_Command) {
|
||||||
|
if(data == 0) {
|
||||||
|
rtc_mode = RTCM_Write;
|
||||||
|
rtc_index = 0;
|
||||||
|
} else if(data == 4) {
|
||||||
|
rtc_mode = RTCM_Ready;
|
||||||
|
rtc_index = -1;
|
||||||
|
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
|
||||||
|
} else {
|
||||||
|
//unknown behavior
|
||||||
|
rtc_mode = RTCM_Ready;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SRTC::SRTC() {
|
||||||
|
}
|
||||||
22
bsnes/chip/srtc/srtc.hpp
Executable file
22
bsnes/chip/srtc/srtc.hpp
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
class SRTC : public MMIO {
|
||||||
|
public:
|
||||||
|
void update_time();
|
||||||
|
unsigned weekday(unsigned year, unsigned month, unsigned day);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read (unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
SRTC();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const unsigned months[12];
|
||||||
|
enum RTC_Mode { RTCM_Ready, RTCM_Command, RTCM_Read, RTCM_Write } rtc_mode;
|
||||||
|
signed rtc_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SRTC srtc;
|
||||||
87
bsnes/chip/st010/st010.cpp
Executable file
87
bsnes/chip/st010/st010.cpp
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define ST010_CPP
|
||||||
|
|
||||||
|
#include "st010.hpp"
|
||||||
|
#include "st010_data.hpp"
|
||||||
|
#include "st010_op.cpp"
|
||||||
|
|
||||||
|
int16 ST010::sin(int16 theta) {
|
||||||
|
return sin_table[(theta >> 8) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 ST010::cos(int16 theta) {
|
||||||
|
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 ST010::readb(uint16 addr) {
|
||||||
|
return ram[addr & 0xfff];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 ST010::readw(uint16 addr) {
|
||||||
|
return (readb(addr + 0) << 0) |
|
||||||
|
(readb(addr + 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ST010::readd(uint16 addr) {
|
||||||
|
return (readb(addr + 0) << 0) |
|
||||||
|
(readb(addr + 1) << 8) |
|
||||||
|
(readb(addr + 2) << 16) |
|
||||||
|
(readb(addr + 3) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::writeb(uint16 addr, uint8 data) {
|
||||||
|
ram[addr & 0xfff] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::writew(uint16 addr, uint16 data) {
|
||||||
|
writeb(addr + 0, data);
|
||||||
|
writeb(addr + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::writed(uint16 addr, uint32 data) {
|
||||||
|
writeb(addr + 0, data);
|
||||||
|
writeb(addr + 1, data >> 8);
|
||||||
|
writeb(addr + 2, data >> 16);
|
||||||
|
writeb(addr + 3, data >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void ST010::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::reset() {
|
||||||
|
memset(ram, 0x00, sizeof ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
uint8 ST010::read(unsigned addr) {
|
||||||
|
return readb(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::write(unsigned addr, uint8 data) {
|
||||||
|
writeb(addr, data);
|
||||||
|
|
||||||
|
if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
|
||||||
|
switch(ram[0x0020]) {
|
||||||
|
case 0x01: op_01(); break;
|
||||||
|
case 0x02: op_02(); break;
|
||||||
|
case 0x03: op_03(); break;
|
||||||
|
case 0x04: op_04(); break;
|
||||||
|
case 0x05: op_05(); break;
|
||||||
|
case 0x06: op_06(); break;
|
||||||
|
case 0x07: op_07(); break;
|
||||||
|
case 0x08: op_08(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ram[0x0021] &= ~0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
bsnes/chip/st010/st010.hpp
Executable file
42
bsnes/chip/st010/st010.hpp
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
class ST010 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x1000];
|
||||||
|
static const int16 sin_table[256];
|
||||||
|
static const int16 mode7_scale[176];
|
||||||
|
static const uint8 arctan[32][32];
|
||||||
|
|
||||||
|
//interfaces to sin table
|
||||||
|
int16 sin(int16 theta);
|
||||||
|
int16 cos(int16 theta);
|
||||||
|
|
||||||
|
//interfaces to ram buffer
|
||||||
|
uint8 readb (uint16 addr);
|
||||||
|
uint16 readw (uint16 addr);
|
||||||
|
uint32 readd (uint16 addr);
|
||||||
|
void writeb(uint16 addr, uint8 data);
|
||||||
|
void writew(uint16 addr, uint16 data);
|
||||||
|
void writed(uint16 addr, uint32 data);
|
||||||
|
|
||||||
|
//opcodes
|
||||||
|
void op_01();
|
||||||
|
void op_02();
|
||||||
|
void op_03();
|
||||||
|
void op_04();
|
||||||
|
void op_05();
|
||||||
|
void op_06();
|
||||||
|
void op_07();
|
||||||
|
void op_08();
|
||||||
|
|
||||||
|
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ST010 st010;
|
||||||
126
bsnes/chip/st010/st010_data.hpp
Executable file
126
bsnes/chip/st010/st010_data.hpp
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
const int16 ST010::sin_table[256] = {
|
||||||
|
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
||||||
|
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
||||||
|
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
||||||
|
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
|
||||||
|
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
|
||||||
|
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
|
||||||
|
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
|
||||||
|
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
|
||||||
|
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
|
||||||
|
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
|
||||||
|
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
|
||||||
|
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
|
||||||
|
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
|
||||||
|
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
|
||||||
|
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
|
||||||
|
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
|
||||||
|
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
|
||||||
|
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
|
||||||
|
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
|
||||||
|
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
|
||||||
|
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
|
||||||
|
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
|
||||||
|
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
|
||||||
|
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
|
||||||
|
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
|
||||||
|
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
|
||||||
|
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
|
||||||
|
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
|
||||||
|
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
|
||||||
|
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
|
||||||
|
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
|
||||||
|
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 ST010::mode7_scale[176] = {
|
||||||
|
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
||||||
|
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
||||||
|
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
||||||
|
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
|
||||||
|
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
|
||||||
|
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
|
||||||
|
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
|
||||||
|
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
|
||||||
|
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
|
||||||
|
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
|
||||||
|
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
|
||||||
|
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
|
||||||
|
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
|
||||||
|
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
|
||||||
|
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
|
||||||
|
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
|
||||||
|
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
|
||||||
|
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
|
||||||
|
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
|
||||||
|
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
|
||||||
|
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
|
||||||
|
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8 ST010::arctan[32][32] = {
|
||||||
|
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
||||||
|
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
||||||
|
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
|
||||||
|
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
|
||||||
|
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
|
||||||
|
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
|
||||||
|
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
|
||||||
|
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
|
||||||
|
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
|
||||||
|
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||||||
|
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
|
||||||
|
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
|
||||||
|
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
|
||||||
|
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
|
||||||
|
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
|
||||||
|
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
|
||||||
|
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
|
||||||
|
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
|
||||||
|
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
|
||||||
|
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
|
||||||
|
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
|
||||||
|
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
|
||||||
|
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
|
||||||
|
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
|
||||||
|
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
|
||||||
|
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
|
||||||
|
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
|
||||||
|
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
|
||||||
|
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
|
||||||
|
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
|
||||||
|
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
|
||||||
|
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
|
||||||
|
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
|
||||||
|
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
|
||||||
|
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
|
||||||
|
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
|
||||||
|
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
|
||||||
|
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
|
||||||
|
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
|
||||||
|
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
|
||||||
|
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
|
||||||
|
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
|
||||||
|
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
|
||||||
|
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
|
||||||
|
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
|
||||||
|
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
|
||||||
|
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
|
||||||
|
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
|
||||||
|
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
||||||
|
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
||||||
|
};
|
||||||
261
bsnes/chip/st010/st010_op.cpp
Executable file
261
bsnes/chip/st010/st010_op.cpp
Executable file
@ -0,0 +1,261 @@
|
|||||||
|
#ifdef ST010_CPP
|
||||||
|
|
||||||
|
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
||||||
|
//bsnes port - Copyright (C) 2007 byuu
|
||||||
|
|
||||||
|
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
|
||||||
|
if((x0 < 0) && (y0 < 0)) {
|
||||||
|
x1 = -x0;
|
||||||
|
y1 = -y0;
|
||||||
|
quadrant = -0x8000;
|
||||||
|
} else if(x0 < 0) {
|
||||||
|
x1 = y0;
|
||||||
|
y1 = -x0;
|
||||||
|
quadrant = -0x4000;
|
||||||
|
} else if(y0 < 0) {
|
||||||
|
x1 = -y0;
|
||||||
|
y1 = x0;
|
||||||
|
quadrant = 0x4000;
|
||||||
|
} else {
|
||||||
|
x1 = x0;
|
||||||
|
y1 = y0;
|
||||||
|
quadrant = 0x0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((x1 > 0x1f) || (y1 > 0x1f)) {
|
||||||
|
if(x1 > 1) { x1 >>= 1; }
|
||||||
|
if(y1 > 1) { y1 >>= 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(y1 == 0) { quadrant += 0x4000; }
|
||||||
|
|
||||||
|
theta = (arctan[y1][x1] << 8) ^ quadrant;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void ST010::op_01() {
|
||||||
|
int16 x0 = readw(0x0000);
|
||||||
|
int16 y0 = readw(0x0002);
|
||||||
|
int16 x1, y1, quadrant, theta;
|
||||||
|
|
||||||
|
op_01(x0, y0, x1, y1, quadrant, theta);
|
||||||
|
|
||||||
|
writew(0x0000, x1);
|
||||||
|
writew(0x0002, y1);
|
||||||
|
writew(0x0004, quadrant);
|
||||||
|
//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
|
||||||
|
writew(0x0010, theta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_02() {
|
||||||
|
int16 positions = readw(0x0024);
|
||||||
|
uint16 *places = (uint16*)(ram + 0x0040);
|
||||||
|
uint16 *drivers = (uint16*)(ram + 0x0080);
|
||||||
|
|
||||||
|
bool sorted;
|
||||||
|
uint16 temp;
|
||||||
|
if(positions > 1) {
|
||||||
|
do {
|
||||||
|
sorted = true;
|
||||||
|
for(int i = 0; i < positions - 1; i++) {
|
||||||
|
if(places[i] < places[i + 1]) {
|
||||||
|
temp = places[i + 1];
|
||||||
|
places[i + 1] = places[i];
|
||||||
|
places[i] = temp;
|
||||||
|
|
||||||
|
temp = drivers[i + 1];
|
||||||
|
drivers[i + 1] = drivers[i];
|
||||||
|
drivers[i] = temp;
|
||||||
|
|
||||||
|
sorted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
positions--;
|
||||||
|
} while(!sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_03() {
|
||||||
|
int16 x0 = readw(0x0000);
|
||||||
|
int16 y0 = readw(0x0002);
|
||||||
|
int16 multiplier = readw(0x0004);
|
||||||
|
int32 x1, y1;
|
||||||
|
|
||||||
|
x1 = x0 * multiplier << 1;
|
||||||
|
y1 = y0 * multiplier << 1;
|
||||||
|
|
||||||
|
writed(0x0010, x1);
|
||||||
|
writed(0x0014, y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_04() {
|
||||||
|
int16 x = readw(0x0000);
|
||||||
|
int16 y = readw(0x0002);
|
||||||
|
int16 square;
|
||||||
|
//calculate the vector length of (x,y)
|
||||||
|
square = (int16)sqrt((double)(y * y + x * x));
|
||||||
|
|
||||||
|
writew(0x0010, square);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_05() {
|
||||||
|
int32 dx, dy;
|
||||||
|
int16 a1, b1, c1;
|
||||||
|
uint16 o1;
|
||||||
|
bool wrap = false;
|
||||||
|
|
||||||
|
//target (x,y) coordinates
|
||||||
|
int16 ypos_max = readw(0x00c0);
|
||||||
|
int16 xpos_max = readw(0x00c2);
|
||||||
|
|
||||||
|
//current coordinates and direction
|
||||||
|
int32 ypos = readd(0x00c4);
|
||||||
|
int32 xpos = readd(0x00c8);
|
||||||
|
uint16 rot = readw(0x00cc);
|
||||||
|
|
||||||
|
//physics
|
||||||
|
uint16 speed = readw(0x00d4);
|
||||||
|
uint16 accel = readw(0x00d6);
|
||||||
|
uint16 speed_max = readw(0x00d8);
|
||||||
|
|
||||||
|
//special condition acknowledgement
|
||||||
|
int16 system = readw(0x00da);
|
||||||
|
int16 flags = readw(0x00dc);
|
||||||
|
|
||||||
|
//new target coordinates
|
||||||
|
int16 ypos_new = readw(0x00de);
|
||||||
|
int16 xpos_new = readw(0x00e0);
|
||||||
|
|
||||||
|
//mask upper bit
|
||||||
|
xpos_new &= 0x7fff;
|
||||||
|
|
||||||
|
//get the current distance
|
||||||
|
dx = xpos_max - (xpos >> 16);
|
||||||
|
dy = ypos_max - (ypos >> 16);
|
||||||
|
|
||||||
|
//quirk: clear and move in9
|
||||||
|
writew(0x00d2, 0xffff);
|
||||||
|
writew(0x00da, 0x0000);
|
||||||
|
|
||||||
|
//grab the target angle
|
||||||
|
op_01(dy, dx, a1, b1, c1, (int16&)o1);
|
||||||
|
|
||||||
|
//check for wrapping
|
||||||
|
if(abs(o1 - rot) > 0x8000) {
|
||||||
|
o1 += 0x8000;
|
||||||
|
rot += 0x8000;
|
||||||
|
wrap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 old_speed = speed;
|
||||||
|
|
||||||
|
//special case
|
||||||
|
if(abs(o1 - rot) == 0x8000) {
|
||||||
|
speed = 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
//slow down for sharp curves
|
||||||
|
else if(abs(o1 - rot) >= 0x1000) {
|
||||||
|
uint32 slow = abs(o1 - rot);
|
||||||
|
slow >>= 4; //scaling
|
||||||
|
speed -= slow;
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise accelerate
|
||||||
|
else {
|
||||||
|
speed += accel;
|
||||||
|
if(speed > speed_max) {
|
||||||
|
speed = speed_max; //clip speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//prevent negative/positive overflow
|
||||||
|
if(abs(old_speed - speed) > 0x8000) {
|
||||||
|
if(old_speed < speed) { speed = 0; }
|
||||||
|
else speed = 0xff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
//adjust direction by so many degrees
|
||||||
|
//be careful of negative adjustments
|
||||||
|
if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
|
||||||
|
if(o1 < rot) { rot -= 0x280; }
|
||||||
|
else if(o1 > rot) { rot += 0x280; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//turn of wrapping
|
||||||
|
if(wrap) { rot -= 0x8000; }
|
||||||
|
|
||||||
|
//now check the distances (store for later)
|
||||||
|
dx = (xpos_max << 16) - xpos;
|
||||||
|
dy = (ypos_max << 16) - ypos;
|
||||||
|
dx >>= 16;
|
||||||
|
dy >>= 16;
|
||||||
|
|
||||||
|
//if we're in so many units of the target, signal it
|
||||||
|
if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
|
||||||
|
//announce our new destination and flag it
|
||||||
|
xpos_max = xpos_new & 0x7fff;
|
||||||
|
ypos_max = ypos_new;
|
||||||
|
flags |= 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update position
|
||||||
|
xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||||
|
ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
|
||||||
|
|
||||||
|
//quirk: mask upper byte
|
||||||
|
xpos &= 0x1fffffff;
|
||||||
|
ypos &= 0x1fffffff;
|
||||||
|
|
||||||
|
writew(0x00c0, ypos_max);
|
||||||
|
writew(0x00c2, xpos_max);
|
||||||
|
writed(0x00c4, ypos);
|
||||||
|
writed(0x00c8, xpos);
|
||||||
|
writew(0x00cc, rot);
|
||||||
|
writew(0x00d4, speed);
|
||||||
|
writew(0x00dc, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_06() {
|
||||||
|
int16 multiplicand = readw(0x0000);
|
||||||
|
int16 multiplier = readw(0x0002);
|
||||||
|
int32 product;
|
||||||
|
|
||||||
|
product = multiplicand * multiplier << 1;
|
||||||
|
|
||||||
|
writed(0x0010, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_07() {
|
||||||
|
int16 theta = readw(0x0000);
|
||||||
|
|
||||||
|
int16 data;
|
||||||
|
for(int i = 0, offset = 0; i < 176; i++) {
|
||||||
|
data = mode7_scale[i] * cos(theta) >> 15;
|
||||||
|
writew(0x00f0 + offset, data);
|
||||||
|
writew(0x0510 + offset, data);
|
||||||
|
|
||||||
|
data = mode7_scale[i] * sin(theta) >> 15;
|
||||||
|
writew(0x0250 + offset, data);
|
||||||
|
if(data) { data = ~data; }
|
||||||
|
writew(0x03b0 + offset, data);
|
||||||
|
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST010::op_08() {
|
||||||
|
int16 x0 = readw(0x0000);
|
||||||
|
int16 y0 = readw(0x0002);
|
||||||
|
int16 theta = readw(0x0004);
|
||||||
|
int16 x1, y1;
|
||||||
|
|
||||||
|
x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
|
||||||
|
y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
|
||||||
|
|
||||||
|
writew(0x0010, x1);
|
||||||
|
writew(0x0012, y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
1
bsnes/clean.bat
Executable file
1
bsnes/clean.bat
Executable file
@ -0,0 +1 @@
|
|||||||
|
@mingw32-make platform=win compiler=mingw32-gcc clean
|
||||||
1
bsnes/clean.sh
Executable file
1
bsnes/clean.sh
Executable file
@ -0,0 +1 @@
|
|||||||
|
make platform=x compiler=gcc clean
|
||||||
17
bsnes/cpu/cpu.cpp
Executable file
17
bsnes/cpu/cpu.cpp
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define CPU_CPP
|
||||||
|
|
||||||
|
#include "dcpu.cpp"
|
||||||
|
|
||||||
|
void CPU::power() {
|
||||||
|
cpu_version = snes.config.cpu.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::reset() {
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU::CPU() {
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU::~CPU() {
|
||||||
|
}
|
||||||
74
bsnes/cpu/cpu.hpp
Executable file
74
bsnes/cpu/cpu.hpp
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
class CPU : public MMIO {
|
||||||
|
public:
|
||||||
|
virtual void enter() = 0;
|
||||||
|
|
||||||
|
//CPU version number
|
||||||
|
//* 1 and 2 are known
|
||||||
|
//* reported by $4210
|
||||||
|
//* affects timing (DRAM refresh, HDMA init, etc)
|
||||||
|
uint8 cpu_version;
|
||||||
|
|
||||||
|
virtual uint8 pio() = 0;
|
||||||
|
virtual bool joylatch() = 0;
|
||||||
|
virtual uint8 port_read(uint8 port) = 0;
|
||||||
|
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||||
|
|
||||||
|
#include "cpuregs.hpp"
|
||||||
|
regs_t regs;
|
||||||
|
|
||||||
|
virtual void scanline() = 0;
|
||||||
|
virtual void power();
|
||||||
|
virtual void reset();
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* in opcode-based CPU emulators, the main emulation routine
|
||||||
|
* will only be able to call the disassemble_opcode() function
|
||||||
|
* on clean opcode edges. but with cycle-based CPU emulators,
|
||||||
|
* the CPU may be in the middle of executing an opcode when the
|
||||||
|
* emulator (e.g. debugger) wants to disassemble an opcode. this
|
||||||
|
* would mean that important registers may not reflect what they
|
||||||
|
* did at the start of the opcode (especially regs.pc), so in
|
||||||
|
* cycle-based emulators, this function should be overridden to
|
||||||
|
* reflect whether or not an opcode has only been partially
|
||||||
|
* executed. if not, the debugger should abort attempts to skip,
|
||||||
|
* disable, or disassemble the current opcode.
|
||||||
|
*****/
|
||||||
|
virtual bool in_opcode() { return false; }
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* opcode disassembler
|
||||||
|
*****/
|
||||||
|
enum {
|
||||||
|
OPTYPE_DP = 0, //dp
|
||||||
|
OPTYPE_DPX, //dp,x
|
||||||
|
OPTYPE_DPY, //dp,y
|
||||||
|
OPTYPE_IDP, //(dp)
|
||||||
|
OPTYPE_IDPX, //(dp,x)
|
||||||
|
OPTYPE_IDPY, //(dp),y
|
||||||
|
OPTYPE_ILDP, //[dp]
|
||||||
|
OPTYPE_ILDPY, //[dp],y
|
||||||
|
OPTYPE_ADDR, //addr
|
||||||
|
OPTYPE_ADDRX, //addr,x
|
||||||
|
OPTYPE_ADDRY, //addr,y
|
||||||
|
OPTYPE_IADDRX, //(addr,x)
|
||||||
|
OPTYPE_ILADDR, //[addr]
|
||||||
|
OPTYPE_LONG, //long
|
||||||
|
OPTYPE_LONGX, //long, x
|
||||||
|
OPTYPE_SR, //sr,s
|
||||||
|
OPTYPE_ISRY, //(sr,s),y
|
||||||
|
OPTYPE_ADDR_PC, //pbr:addr
|
||||||
|
OPTYPE_IADDR_PC, //pbr:(addr)
|
||||||
|
OPTYPE_RELB, //relb
|
||||||
|
OPTYPE_RELW, //relw
|
||||||
|
};
|
||||||
|
|
||||||
|
void disassemble_opcode(char *output);
|
||||||
|
uint8 dreadb(uint32 addr);
|
||||||
|
uint16 dreadw(uint32 addr);
|
||||||
|
uint32 dreadl(uint32 addr);
|
||||||
|
uint32 decode(uint8 offset_type, uint32 addr);
|
||||||
|
uint8 opcode_length();
|
||||||
|
|
||||||
|
CPU();
|
||||||
|
virtual ~CPU();
|
||||||
|
};
|
||||||
74
bsnes/cpu/cpuregs.hpp
Executable file
74
bsnes/cpu/cpuregs.hpp
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
struct flag_t {
|
||||||
|
bool n, v, m, x, d, i, z, c;
|
||||||
|
|
||||||
|
inline operator unsigned() const {
|
||||||
|
return (n << 7) + (v << 6) + (m << 5) + (x << 4)
|
||||||
|
+ (d << 3) + (i << 2) + (z << 1) + (c << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned operator=(uint8_t data) {
|
||||||
|
n = data & 0x80; v = data & 0x40; m = data & 0x20; x = data & 0x10;
|
||||||
|
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); }
|
||||||
|
inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); }
|
||||||
|
inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); }
|
||||||
|
|
||||||
|
flag_t() : n(0), v(0), m(0), x(0), d(0), i(0), z(0), c(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reg16_t {
|
||||||
|
union {
|
||||||
|
uint16 w;
|
||||||
|
struct { uint8 order_lsb2(l, h); };
|
||||||
|
};
|
||||||
|
|
||||||
|
inline operator unsigned() const { return w; }
|
||||||
|
inline unsigned operator = (unsigned i) { return w = i; }
|
||||||
|
inline unsigned operator |= (unsigned i) { return w |= i; }
|
||||||
|
inline unsigned operator ^= (unsigned i) { return w ^= i; }
|
||||||
|
inline unsigned operator &= (unsigned i) { return w &= i; }
|
||||||
|
inline unsigned operator <<= (unsigned i) { return w <<= i; }
|
||||||
|
inline unsigned operator >>= (unsigned i) { return w >>= i; }
|
||||||
|
inline unsigned operator += (unsigned i) { return w += i; }
|
||||||
|
inline unsigned operator -= (unsigned i) { return w -= i; }
|
||||||
|
inline unsigned operator *= (unsigned i) { return w *= i; }
|
||||||
|
inline unsigned operator /= (unsigned i) { return w /= i; }
|
||||||
|
inline unsigned operator %= (unsigned i) { return w %= i; }
|
||||||
|
|
||||||
|
reg16_t() : w(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reg24_t {
|
||||||
|
union {
|
||||||
|
uint32 d;
|
||||||
|
struct { uint16 order_lsb2(w, wh); };
|
||||||
|
struct { uint8 order_lsb4(l, h, b, bh); };
|
||||||
|
};
|
||||||
|
|
||||||
|
inline operator unsigned() const { return d; }
|
||||||
|
inline unsigned operator = (unsigned i) { return d = uclip<24>(i); }
|
||||||
|
inline unsigned operator |= (unsigned i) { return d = uclip<24>(d | i); }
|
||||||
|
inline unsigned operator ^= (unsigned i) { return d = uclip<24>(d ^ i); }
|
||||||
|
inline unsigned operator &= (unsigned i) { return d = uclip<24>(d & i); }
|
||||||
|
inline unsigned operator <<= (unsigned i) { return d = uclip<24>(d << i); }
|
||||||
|
inline unsigned operator >>= (unsigned i) { return d = uclip<24>(d >> i); }
|
||||||
|
inline unsigned operator += (unsigned i) { return d = uclip<24>(d + i); }
|
||||||
|
inline unsigned operator -= (unsigned i) { return d = uclip<24>(d - i); }
|
||||||
|
inline unsigned operator *= (unsigned i) { return d = uclip<24>(d * i); }
|
||||||
|
inline unsigned operator /= (unsigned i) { return d = uclip<24>(d / i); }
|
||||||
|
inline unsigned operator %= (unsigned i) { return d = uclip<24>(d % i); }
|
||||||
|
|
||||||
|
reg24_t() : d(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct regs_t {
|
||||||
|
reg24_t pc;
|
||||||
|
reg16_t a, x, y, s, d;
|
||||||
|
flag_t p;
|
||||||
|
uint8_t db, mdr;
|
||||||
|
bool e;
|
||||||
|
regs_t() : db(0), mdr(0), e(false) {}
|
||||||
|
};
|
||||||
483
bsnes/cpu/dcpu.cpp
Executable file
483
bsnes/cpu/dcpu.cpp
Executable file
@ -0,0 +1,483 @@
|
|||||||
|
#ifdef CPU_CPP
|
||||||
|
|
||||||
|
uint8 CPU::dreadb(uint32 addr) {
|
||||||
|
if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) {
|
||||||
|
//$[00-3f|80-bf]:[2000-5fff]
|
||||||
|
//do not read MMIO registers within debugger
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
return bus.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 CPU::dreadw(uint32 addr) {
|
||||||
|
uint16 r;
|
||||||
|
r = dreadb((addr + 0) & 0xffffff) << 0;
|
||||||
|
r |= dreadb((addr + 1) & 0xffffff) << 8;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 CPU::dreadl(uint32 addr) {
|
||||||
|
uint32 r;
|
||||||
|
r = dreadb((addr + 0) & 0xffffff) << 0;
|
||||||
|
r |= dreadb((addr + 1) & 0xffffff) << 8;
|
||||||
|
r |= dreadb((addr + 2) & 0xffffff) << 16;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 CPU::decode(uint8 offset_type, uint32 addr) {
|
||||||
|
uint32 r = 0;
|
||||||
|
|
||||||
|
switch(offset_type) {
|
||||||
|
case OPTYPE_DP:
|
||||||
|
r = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||||
|
break;
|
||||||
|
case OPTYPE_DPX:
|
||||||
|
r = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
|
||||||
|
break;
|
||||||
|
case OPTYPE_DPY:
|
||||||
|
r = (regs.d + regs.y + (addr & 0xffff)) & 0xffff;
|
||||||
|
break;
|
||||||
|
case OPTYPE_IDP:
|
||||||
|
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||||
|
r = (regs.db << 16) + dreadw(addr);
|
||||||
|
break;
|
||||||
|
case OPTYPE_IDPX:
|
||||||
|
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
|
||||||
|
r = (regs.db << 16) + dreadw(addr);
|
||||||
|
break;
|
||||||
|
case OPTYPE_IDPY:
|
||||||
|
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||||
|
r = (regs.db << 16) + dreadw(addr) + regs.y;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ILDP:
|
||||||
|
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||||
|
r = dreadl(addr);
|
||||||
|
break;
|
||||||
|
case OPTYPE_ILDPY:
|
||||||
|
addr = (regs.d + (addr & 0xffff)) & 0xffff;
|
||||||
|
r = dreadl(addr) + regs.y;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ADDR:
|
||||||
|
r = (regs.db << 16) + (addr & 0xffff);
|
||||||
|
break;
|
||||||
|
case OPTYPE_ADDR_PC:
|
||||||
|
r = (regs.pc.b << 16) + (addr & 0xffff);
|
||||||
|
break;
|
||||||
|
case OPTYPE_ADDRX:
|
||||||
|
r = (regs.db << 16) + (addr & 0xffff) + regs.x;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ADDRY:
|
||||||
|
r = (regs.db << 16) + (addr & 0xffff) + regs.y;
|
||||||
|
break;
|
||||||
|
case OPTYPE_IADDR_PC:
|
||||||
|
r = (regs.pc.b << 16) + (addr & 0xffff);
|
||||||
|
break;
|
||||||
|
case OPTYPE_IADDRX:
|
||||||
|
r = (regs.pc.b << 16) + ((addr + regs.x) & 0xffff);
|
||||||
|
break;
|
||||||
|
case OPTYPE_ILADDR:
|
||||||
|
r = addr;
|
||||||
|
break;
|
||||||
|
case OPTYPE_LONG:
|
||||||
|
r = addr;
|
||||||
|
break;
|
||||||
|
case OPTYPE_LONGX:
|
||||||
|
r = (addr + regs.x);
|
||||||
|
break;
|
||||||
|
case OPTYPE_SR:
|
||||||
|
r = (regs.s + (addr & 0xff)) & 0xffff;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ISRY:
|
||||||
|
addr = (regs.s + (addr & 0xff)) & 0xffff;
|
||||||
|
r = (regs.db << 16) + dreadw(addr) + regs.y;
|
||||||
|
break;
|
||||||
|
case OPTYPE_RELB:
|
||||||
|
r = (regs.pc.b << 16) + ((regs.pc.w + 2) & 0xffff);
|
||||||
|
r += int8(addr);
|
||||||
|
break;
|
||||||
|
case OPTYPE_RELW:
|
||||||
|
r = (regs.pc.b << 16) + ((regs.pc.w + 3) & 0xffff);
|
||||||
|
r += int16(addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(r & 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::disassemble_opcode(char *output) {
|
||||||
|
static reg24_t pc;
|
||||||
|
char t[256];
|
||||||
|
char *s = output;
|
||||||
|
|
||||||
|
if(in_opcode() == true) {
|
||||||
|
strcpy(s, "?????? <CPU within opcode>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pc.d = regs.pc.d;
|
||||||
|
sprintf(s, "%.6x ", (uint32)pc.d);
|
||||||
|
|
||||||
|
uint8 op = dreadb(pc.d); pc.w++;
|
||||||
|
uint8 op0 = dreadb(pc.d); pc.w++;
|
||||||
|
uint8 op1 = dreadb(pc.d); pc.w++;
|
||||||
|
uint8 op2 = dreadb(pc.d);
|
||||||
|
|
||||||
|
#define op8 ((op0))
|
||||||
|
#define op16 ((op0) | (op1 << 8))
|
||||||
|
#define op24 ((op0) | (op1 << 8) | (op2 << 16))
|
||||||
|
#define a8 (regs.e || regs.p.m)
|
||||||
|
#define x8 (regs.e || regs.p.x)
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
case 0x00: sprintf(t, "brk #$%.2x ", op8); break;
|
||||||
|
case 0x01: sprintf(t, "ora ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0x02: sprintf(t, "cop #$%.2x ", op8); break;
|
||||||
|
case 0x03: sprintf(t, "ora $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0x04: sprintf(t, "tsb $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x05: sprintf(t, "ora $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x06: sprintf(t, "asl $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x07: sprintf(t, "ora [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0x08: sprintf(t, "php "); break;
|
||||||
|
case 0x09: if(a8)sprintf(t, "ora #$%.2x ", op8);
|
||||||
|
else sprintf(t, "ora #$%.4x ", op16); break;
|
||||||
|
case 0x0a: sprintf(t, "asl a "); break;
|
||||||
|
case 0x0b: sprintf(t, "phd "); break;
|
||||||
|
case 0x0c: sprintf(t, "tsb $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x0d: sprintf(t, "ora $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x0e: sprintf(t, "asl $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x0f: sprintf(t, "ora $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x10: sprintf(t, "bpl $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x11: sprintf(t, "ora ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0x12: sprintf(t, "ora ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0x13: sprintf(t, "ora ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0x14: sprintf(t, "trb $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x15: sprintf(t, "ora $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x16: sprintf(t, "asl $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x17: sprintf(t, "ora [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0x18: sprintf(t, "clc "); break;
|
||||||
|
case 0x19: sprintf(t, "ora $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0x1a: sprintf(t, "inc "); break;
|
||||||
|
case 0x1b: sprintf(t, "tcs "); break;
|
||||||
|
case 0x1c: sprintf(t, "trb $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x1d: sprintf(t, "ora $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x1e: sprintf(t, "asl $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x1f: sprintf(t, "ora $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0x20: sprintf(t, "jsr $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break;
|
||||||
|
case 0x21: sprintf(t, "and ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0x22: sprintf(t, "jsl $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x23: sprintf(t, "and $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0x24: sprintf(t, "bit $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x25: sprintf(t, "and $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x26: sprintf(t, "rol $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x27: sprintf(t, "and [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0x28: sprintf(t, "plp "); break;
|
||||||
|
case 0x29: if(a8)sprintf(t, "and #$%.2x ", op8);
|
||||||
|
else sprintf(t, "and #$%.4x ", op16); break;
|
||||||
|
case 0x2a: sprintf(t, "rol a "); break;
|
||||||
|
case 0x2b: sprintf(t, "pld "); break;
|
||||||
|
case 0x2c: sprintf(t, "bit $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x2d: sprintf(t, "and $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x2e: sprintf(t, "rol $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x2f: sprintf(t, "and $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x30: sprintf(t, "bmi $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x31: sprintf(t, "and ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0x32: sprintf(t, "and ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0x33: sprintf(t, "and ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0x34: sprintf(t, "bit $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x35: sprintf(t, "and $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x36: sprintf(t, "rol $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x37: sprintf(t, "and [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0x38: sprintf(t, "sec "); break;
|
||||||
|
case 0x39: sprintf(t, "and $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0x3a: sprintf(t, "dec "); break;
|
||||||
|
case 0x3b: sprintf(t, "tsc "); break;
|
||||||
|
case 0x3c: sprintf(t, "bit $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x3d: sprintf(t, "and $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x3e: sprintf(t, "rol $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x3f: sprintf(t, "and $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0x40: sprintf(t, "rti "); break;
|
||||||
|
case 0x41: sprintf(t, "eor ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0x42: sprintf(t, "wdm "); break;
|
||||||
|
case 0x43: sprintf(t, "eor $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0x44: sprintf(t, "mvp $%.2x,$%.2x ", op1, op8); break;
|
||||||
|
case 0x45: sprintf(t, "eor $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x46: sprintf(t, "lsr $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x47: sprintf(t, "eor [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0x48: sprintf(t, "pha "); break;
|
||||||
|
case 0x49: if(a8)sprintf(t, "eor #$%.2x ", op8);
|
||||||
|
else sprintf(t, "eor #$%.4x ", op16); break;
|
||||||
|
case 0x4a: sprintf(t, "lsr a "); break;
|
||||||
|
case 0x4b: sprintf(t, "phk "); break;
|
||||||
|
case 0x4c: sprintf(t, "jmp $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break;
|
||||||
|
case 0x4d: sprintf(t, "eor $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x4e: sprintf(t, "lsr $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x4f: sprintf(t, "eor $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x50: sprintf(t, "bvc $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x51: sprintf(t, "eor ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0x52: sprintf(t, "eor ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0x53: sprintf(t, "eor ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0x54: sprintf(t, "mvn $%.2x,$%.2x ", op1, op8); break;
|
||||||
|
case 0x55: sprintf(t, "eor $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x56: sprintf(t, "lsr $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x57: sprintf(t, "eor [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0x58: sprintf(t, "cli "); break;
|
||||||
|
case 0x59: sprintf(t, "eor $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0x5a: sprintf(t, "phy "); break;
|
||||||
|
case 0x5b: sprintf(t, "tcd "); break;
|
||||||
|
case 0x5c: sprintf(t, "jml $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x5d: sprintf(t, "eor $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x5e: sprintf(t, "lsr $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x5f: sprintf(t, "eor $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0x60: sprintf(t, "rts "); break;
|
||||||
|
case 0x61: sprintf(t, "adc ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0x62: sprintf(t, "per $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x63: sprintf(t, "adc $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0x64: sprintf(t, "stz $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x65: sprintf(t, "adc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x66: sprintf(t, "ror $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x67: sprintf(t, "adc [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0x68: sprintf(t, "pla "); break;
|
||||||
|
case 0x69: if(a8)sprintf(t, "adc #$%.2x ", op8);
|
||||||
|
else sprintf(t, "adc #$%.4x ", op16); break;
|
||||||
|
case 0x6a: sprintf(t, "ror a "); break;
|
||||||
|
case 0x6b: sprintf(t, "rtl "); break;
|
||||||
|
case 0x6c: sprintf(t, "jmp ($%.4x) [$%.6x]", op16, decode(OPTYPE_IADDR_PC, op16)); break;
|
||||||
|
case 0x6d: sprintf(t, "adc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x6e: sprintf(t, "ror $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x6f: sprintf(t, "adc $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x70: sprintf(t, "bvs $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x71: sprintf(t, "adc ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0x72: sprintf(t, "adc ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0x73: sprintf(t, "adc ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0x74: sprintf(t, "stz $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x75: sprintf(t, "adc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x76: sprintf(t, "ror $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x77: sprintf(t, "adc [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0x78: sprintf(t, "sei "); break;
|
||||||
|
case 0x79: sprintf(t, "adc $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0x7a: sprintf(t, "ply "); break;
|
||||||
|
case 0x7b: sprintf(t, "tdc "); break;
|
||||||
|
case 0x7c: sprintf(t, "jmp ($%.4x,x) [$%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break;
|
||||||
|
case 0x7d: sprintf(t, "adc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x7e: sprintf(t, "ror $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x7f: sprintf(t, "adc $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0x80: sprintf(t, "bra $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x81: sprintf(t, "sta ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0x82: sprintf(t, "brl $%.4x [$%.6x]", uint16(decode(OPTYPE_RELW, op16)), decode(OPTYPE_RELW, op16)); break;
|
||||||
|
case 0x83: sprintf(t, "sta $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0x84: sprintf(t, "sty $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x85: sprintf(t, "sta $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x86: sprintf(t, "stx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0x87: sprintf(t, "sta [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0x88: sprintf(t, "dey "); break;
|
||||||
|
case 0x89: if(a8)sprintf(t, "bit #$%.2x ", op8);
|
||||||
|
else sprintf(t, "bit #$%.4x ", op16); break;
|
||||||
|
case 0x8a: sprintf(t, "txa "); break;
|
||||||
|
case 0x8b: sprintf(t, "phb "); break;
|
||||||
|
case 0x8c: sprintf(t, "sty $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x8d: sprintf(t, "sta $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x8e: sprintf(t, "stx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x8f: sprintf(t, "sta $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0x90: sprintf(t, "bcc $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0x91: sprintf(t, "sta ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0x92: sprintf(t, "sta ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0x93: sprintf(t, "sta ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0x94: sprintf(t, "sty $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x95: sprintf(t, "sta $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0x96: sprintf(t, "stx $%.2x,y [$%.6x]", op8, decode(OPTYPE_DPY, op8)); break;
|
||||||
|
case 0x97: sprintf(t, "sta [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0x98: sprintf(t, "tya "); break;
|
||||||
|
case 0x99: sprintf(t, "sta $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0x9a: sprintf(t, "txs "); break;
|
||||||
|
case 0x9b: sprintf(t, "txy "); break;
|
||||||
|
case 0x9c: sprintf(t, "stz $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0x9d: sprintf(t, "sta $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x9e: sprintf(t, "stz $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0x9f: sprintf(t, "sta $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0xa0: if(x8)sprintf(t, "ldy #$%.2x ", op8);
|
||||||
|
else sprintf(t, "ldy #$%.4x ", op16); break;
|
||||||
|
case 0xa1: sprintf(t, "lda ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0xa2: if(x8)sprintf(t, "ldx #$%.2x ", op8);
|
||||||
|
else sprintf(t, "ldx #$%.4x ", op16); break;
|
||||||
|
case 0xa3: sprintf(t, "lda $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0xa4: sprintf(t, "ldy $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xa5: sprintf(t, "lda $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xa6: sprintf(t, "ldx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xa7: sprintf(t, "lda [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0xa8: sprintf(t, "tay "); break;
|
||||||
|
case 0xa9: if(a8)sprintf(t, "lda #$%.2x ", op8);
|
||||||
|
else sprintf(t, "lda #$%.4x ", op16); break;
|
||||||
|
case 0xaa: sprintf(t, "tax "); break;
|
||||||
|
case 0xab: sprintf(t, "plb "); break;
|
||||||
|
case 0xac: sprintf(t, "ldy $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xad: sprintf(t, "lda $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xae: sprintf(t, "ldx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xaf: sprintf(t, "lda $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0xb0: sprintf(t, "bcs $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0xb1: sprintf(t, "lda ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0xb2: sprintf(t, "lda ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0xb3: sprintf(t, "lda ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0xb4: sprintf(t, "ldy $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xb5: sprintf(t, "lda $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xb6: sprintf(t, "ldx $%.2x,y [$%.6x]", op8, decode(OPTYPE_DPY, op8)); break;
|
||||||
|
case 0xb7: sprintf(t, "lda [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0xb8: sprintf(t, "clv "); break;
|
||||||
|
case 0xb9: sprintf(t, "lda $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0xba: sprintf(t, "tsx "); break;
|
||||||
|
case 0xbb: sprintf(t, "tyx "); break;
|
||||||
|
case 0xbc: sprintf(t, "ldy $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xbd: sprintf(t, "lda $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xbe: sprintf(t, "ldx $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0xbf: sprintf(t, "lda $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0xc0: if(x8)sprintf(t, "cpy #$%.2x ", op8);
|
||||||
|
else sprintf(t, "cpy #$%.4x ", op16); break;
|
||||||
|
case 0xc1: sprintf(t, "cmp ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0xc2: sprintf(t, "rep #$%.2x ", op8); break;
|
||||||
|
case 0xc3: sprintf(t, "cmp $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0xc4: sprintf(t, "cpy $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xc5: sprintf(t, "cmp $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xc6: sprintf(t, "dec $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xc7: sprintf(t, "cmp [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0xc8: sprintf(t, "iny "); break;
|
||||||
|
case 0xc9: if(a8)sprintf(t, "cmp #$%.2x ", op8);
|
||||||
|
else sprintf(t, "cmp #$%.4x ", op16); break;
|
||||||
|
case 0xca: sprintf(t, "dex "); break;
|
||||||
|
case 0xcb: sprintf(t, "wai "); break;
|
||||||
|
case 0xcc: sprintf(t, "cpy $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xcd: sprintf(t, "cmp $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xce: sprintf(t, "dec $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xcf: sprintf(t, "cmp $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0xd0: sprintf(t, "bne $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0xd1: sprintf(t, "cmp ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0xd2: sprintf(t, "cmp ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0xd3: sprintf(t, "cmp ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0xd4: sprintf(t, "pei ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0xd5: sprintf(t, "cmp $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xd6: sprintf(t, "dec $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xd7: sprintf(t, "cmp [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0xd8: sprintf(t, "cld "); break;
|
||||||
|
case 0xd9: sprintf(t, "cmp $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0xda: sprintf(t, "phx "); break;
|
||||||
|
case 0xdb: sprintf(t, "stp "); break;
|
||||||
|
case 0xdc: sprintf(t, "jmp [$%.4x] [$%.6x]", op16, decode(OPTYPE_ILADDR, op16)); break;
|
||||||
|
case 0xdd: sprintf(t, "cmp $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xde: sprintf(t, "dec $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xdf: sprintf(t, "cmp $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
case 0xe0: if(x8)sprintf(t, "cpx #$%.2x ", op8);
|
||||||
|
else sprintf(t, "cpx #$%.4x ", op16); break;
|
||||||
|
case 0xe1: sprintf(t, "sbc ($%.2x,x) [$%.6x]", op8, decode(OPTYPE_IDPX, op8)); break;
|
||||||
|
case 0xe2: sprintf(t, "sep #$%.2x ", op8); break;
|
||||||
|
case 0xe3: sprintf(t, "sbc $%.2x,s [$%.6x]", op8, decode(OPTYPE_SR, op8)); break;
|
||||||
|
case 0xe4: sprintf(t, "cpx $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xe5: sprintf(t, "sbc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xe6: sprintf(t, "inc $%.2x [$%.6x]", op8, decode(OPTYPE_DP, op8)); break;
|
||||||
|
case 0xe7: sprintf(t, "sbc [$%.2x] [$%.6x]", op8, decode(OPTYPE_ILDP, op8)); break;
|
||||||
|
case 0xe8: sprintf(t, "inx "); break;
|
||||||
|
case 0xe9: if(a8)sprintf(t, "sbc #$%.2x ", op8);
|
||||||
|
else sprintf(t, "sbc #$%.4x ", op16); break;
|
||||||
|
case 0xea: sprintf(t, "nop "); break;
|
||||||
|
case 0xeb: sprintf(t, "xba "); break;
|
||||||
|
case 0xec: sprintf(t, "cpx $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xed: sprintf(t, "sbc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xee: sprintf(t, "inc $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xef: sprintf(t, "sbc $%.6x [$%.6x]", op24, decode(OPTYPE_LONG, op24)); break;
|
||||||
|
case 0xf0: sprintf(t, "beq $%.4x [$%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break;
|
||||||
|
case 0xf1: sprintf(t, "sbc ($%.2x),y [$%.6x]", op8, decode(OPTYPE_IDPY, op8)); break;
|
||||||
|
case 0xf2: sprintf(t, "sbc ($%.2x) [$%.6x]", op8, decode(OPTYPE_IDP, op8)); break;
|
||||||
|
case 0xf3: sprintf(t, "sbc ($%.2x,s),y [$%.6x]", op8, decode(OPTYPE_ISRY, op8)); break;
|
||||||
|
case 0xf4: sprintf(t, "pea $%.4x [$%.6x]", op16, decode(OPTYPE_ADDR, op16)); break;
|
||||||
|
case 0xf5: sprintf(t, "sbc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xf6: sprintf(t, "inc $%.2x,x [$%.6x]", op8, decode(OPTYPE_DPX, op8)); break;
|
||||||
|
case 0xf7: sprintf(t, "sbc [$%.2x],y [$%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break;
|
||||||
|
case 0xf8: sprintf(t, "sed "); break;
|
||||||
|
case 0xf9: sprintf(t, "sbc $%.4x,y [$%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break;
|
||||||
|
case 0xfa: sprintf(t, "plx "); break;
|
||||||
|
case 0xfb: sprintf(t, "xce "); break;
|
||||||
|
case 0xfc: sprintf(t, "jsr ($%.4x,x) [$%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break;
|
||||||
|
case 0xfd: sprintf(t, "sbc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xfe: sprintf(t, "inc $%.4x,x [$%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break;
|
||||||
|
case 0xff: sprintf(t, "sbc $%.6x,x [$%.6x]", op24, decode(OPTYPE_LONGX, op24)); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef op8
|
||||||
|
#undef op16
|
||||||
|
#undef op24
|
||||||
|
#undef a8
|
||||||
|
#undef x8
|
||||||
|
|
||||||
|
strcat(s, t);
|
||||||
|
strcat(s, " ");
|
||||||
|
|
||||||
|
sprintf(t, "A:%.4x X:%.4x Y:%.4x S:%.4x D:%.4x DB:%.2x ",
|
||||||
|
regs.a.w, regs.x.w, regs.y.w, regs.s.w, regs.d.w, regs.db);
|
||||||
|
strcat(s, t);
|
||||||
|
|
||||||
|
if(regs.e) {
|
||||||
|
sprintf(t, "%c%c%c%c%c%c%c%c",
|
||||||
|
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
|
||||||
|
regs.p.m ? '1' : '0', regs.p.x ? 'B' : 'b',
|
||||||
|
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
|
||||||
|
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c');
|
||||||
|
} else {
|
||||||
|
sprintf(t, "%c%c%c%c%c%c%c%c",
|
||||||
|
regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v',
|
||||||
|
regs.p.m ? 'M' : 'm', regs.p.x ? 'X' : 'x',
|
||||||
|
regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i',
|
||||||
|
regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c');
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(s, t);
|
||||||
|
strcat(s, " ");
|
||||||
|
|
||||||
|
sprintf(t, "V:%3d H:%4d", ppu.vcounter(), ppu.hcounter());
|
||||||
|
strcat(s, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
//opcode_length() retrieves the length of the next opcode
|
||||||
|
//to be executed. It is used by the debugger to step over,
|
||||||
|
//disable and proceed cpu opcodes.
|
||||||
|
//
|
||||||
|
//5 and 6 are special cases, 5 is used for #consts based on
|
||||||
|
//the A register size, 6 for the X/Y register size. the
|
||||||
|
//rest are literal sizes. There's no need to test for
|
||||||
|
//emulation mode, as regs.p.m/regs.p.x should *always* be
|
||||||
|
//set in emulation mode.
|
||||||
|
|
||||||
|
uint8 CPU::opcode_length() {
|
||||||
|
uint8 op, len;
|
||||||
|
static uint8 op_len_tbl[256] = {
|
||||||
|
//0,1,2,3, 4,5,6,7, 8,9,a,b, c,d,e,f
|
||||||
|
|
||||||
|
2,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x0n
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x1n
|
||||||
|
3,2,4,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x2n
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x3n
|
||||||
|
|
||||||
|
1,2,2,2, 3,2,2,2, 1,5,1,1, 3,3,3,4, //0x4n
|
||||||
|
2,2,2,2, 3,2,2,2, 1,3,1,1, 4,3,3,4, //0x5n
|
||||||
|
1,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x6n
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x7n
|
||||||
|
|
||||||
|
2,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x8n
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x9n
|
||||||
|
6,2,6,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xan
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xbn
|
||||||
|
|
||||||
|
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xcn
|
||||||
|
2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xdn
|
||||||
|
6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen
|
||||||
|
2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn
|
||||||
|
};
|
||||||
|
|
||||||
|
if(in_opcode() == true) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
op = dreadb(regs.pc.d);
|
||||||
|
len = op_len_tbl[op];
|
||||||
|
if(len == 5) return (regs.e || regs.p.m) ? 2 : 3;
|
||||||
|
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ifdef CPU_CPP
|
||||||
4
bsnes/cpu/scpu/core/cc.sh
Executable file
4
bsnes/cpu/scpu/core/cc.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
g++ -c scpugen.cpp -I../../../lib
|
||||||
|
g++ -c ../../../lib/nall/string.cpp -I../../../lib
|
||||||
|
g++ -o scpugen scpugen.o string.o
|
||||||
|
rm *.o
|
||||||
1
bsnes/cpu/scpu/core/clean.sh
Executable file
1
bsnes/cpu/scpu/core/clean.sh
Executable file
@ -0,0 +1 @@
|
|||||||
|
rm scpugen
|
||||||
90
bsnes/cpu/scpu/core/core.cpp
Executable file
90
bsnes/cpu/scpu/core/core.cpp
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
#include "opfn.cpp"
|
||||||
|
|
||||||
|
void sCPU::enter() {
|
||||||
|
initialize:
|
||||||
|
//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);
|
||||||
|
|
||||||
|
loop:
|
||||||
|
if(status.interrupt_pending) {
|
||||||
|
status.interrupt_pending = false;
|
||||||
|
if(status.nmi_pending) {
|
||||||
|
status.nmi_pending = false;
|
||||||
|
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||||
|
} else if(status.irq_pending) {
|
||||||
|
status.irq_pending = false;
|
||||||
|
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||||
|
}
|
||||||
|
op_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
tracer.trace_cpuop(); //traces CPU opcode (only if tracer is enabled)
|
||||||
|
|
||||||
|
status.in_opcode = true;
|
||||||
|
switch(op_readpc()) {
|
||||||
|
#include "op_read.cpp"
|
||||||
|
#include "op_write.cpp"
|
||||||
|
#include "op_rmw.cpp"
|
||||||
|
#include "op_pc.cpp"
|
||||||
|
#include "op_misc.cpp"
|
||||||
|
}
|
||||||
|
status.in_opcode = false;
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::op_irq() {
|
||||||
|
op_read(regs.pc.d);
|
||||||
|
op_io();
|
||||||
|
if(!regs.e) op_writestack(regs.pc.b);
|
||||||
|
op_writestack(regs.pc.h);
|
||||||
|
op_writestack(regs.pc.l);
|
||||||
|
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||||
|
rd.l = op_read(status.interrupt_vector + 0);
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
regs.p.i = 1;
|
||||||
|
regs.p.d = 0;
|
||||||
|
rd.h = op_read(status.interrupt_vector + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
//immediate, 2-cycle opcodes with I/O cycle will become bus read
|
||||||
|
//when an IRQ is to be triggered immediately after opcode completion
|
||||||
|
//this affects the following opcodes:
|
||||||
|
// clc, cld, cli, clv, sec, sed, sei,
|
||||||
|
// tax, tay, txa, txy, tya, tyx,
|
||||||
|
// tcd, tcs, tdc, tsc, tsx, txs,
|
||||||
|
// inc, inx, iny, dec, dex, dey,
|
||||||
|
// asl, lsr, rol, ror, nop, xce.
|
||||||
|
alwaysinline void sCPU::op_io_irq() {
|
||||||
|
if(status.interrupt_pending) {
|
||||||
|
//IRQ pending, modify I/O cycle to bus read cycle, do not increment PC
|
||||||
|
op_read(regs.pc.d);
|
||||||
|
} else {
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_io_cond2() {
|
||||||
|
if(regs.d.l != 0x00) {
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_io_cond4(uint16 x, uint16 y) {
|
||||||
|
if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) {
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_io_cond6(uint16 addr) {
|
||||||
|
if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) {
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
54
bsnes/cpu/scpu/core/core.hpp
Executable file
54
bsnes/cpu/scpu/core/core.hpp
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
reg24_t aa, rd;
|
||||||
|
uint8_t dp, sp;
|
||||||
|
|
||||||
|
void op_irq();
|
||||||
|
|
||||||
|
inline bool in_opcode() { return status.in_opcode; }
|
||||||
|
|
||||||
|
//op_read
|
||||||
|
void op_adc_b();
|
||||||
|
void op_adc_w();
|
||||||
|
void op_and_b();
|
||||||
|
void op_and_w();
|
||||||
|
void op_bit_b();
|
||||||
|
void op_bit_w();
|
||||||
|
void op_cmp_b();
|
||||||
|
void op_cmp_w();
|
||||||
|
void op_cpx_b();
|
||||||
|
void op_cpx_w();
|
||||||
|
void op_cpy_b();
|
||||||
|
void op_cpy_w();
|
||||||
|
void op_eor_b();
|
||||||
|
void op_eor_w();
|
||||||
|
void op_lda_b();
|
||||||
|
void op_lda_w();
|
||||||
|
void op_ldx_b();
|
||||||
|
void op_ldx_w();
|
||||||
|
void op_ldy_b();
|
||||||
|
void op_ldy_w();
|
||||||
|
void op_ora_b();
|
||||||
|
void op_ora_w();
|
||||||
|
void op_sbc_b();
|
||||||
|
void op_sbc_w();
|
||||||
|
//op_rmw
|
||||||
|
void op_inc_b();
|
||||||
|
void op_inc_w();
|
||||||
|
void op_dec_b();
|
||||||
|
void op_dec_w();
|
||||||
|
void op_asl_b();
|
||||||
|
void op_asl_w();
|
||||||
|
void op_lsr_b();
|
||||||
|
void op_lsr_w();
|
||||||
|
void op_rol_b();
|
||||||
|
void op_rol_w();
|
||||||
|
void op_ror_b();
|
||||||
|
void op_ror_w();
|
||||||
|
void op_trb_b();
|
||||||
|
void op_trb_w();
|
||||||
|
void op_tsb_b();
|
||||||
|
void op_tsb_w();
|
||||||
|
|
||||||
|
void op_io_irq();
|
||||||
|
void op_io_cond2();
|
||||||
|
void op_io_cond4(uint16 x, uint16 y);
|
||||||
|
void op_io_cond6(uint16 addr);
|
||||||
298
bsnes/cpu/scpu/core/op_misc.b
Executable file
298
bsnes/cpu/scpu/core/op_misc.b
Executable file
@ -0,0 +1,298 @@
|
|||||||
|
nop(0xea) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
wdm(0x42) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_readpc();
|
||||||
|
}
|
||||||
|
|
||||||
|
xba(0xeb) {
|
||||||
|
1:op_io();
|
||||||
|
2:last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.a.l ^= regs.a.h;
|
||||||
|
regs.a.h ^= regs.a.l;
|
||||||
|
regs.a.l ^= regs.a.h;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
mvn(0x54, ++),
|
||||||
|
mvp(0x44, --) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:sp = op_readpc();
|
||||||
|
3:regs.db = dp;
|
||||||
|
rd.l = op_readlong((sp << 16) | regs.x.w);
|
||||||
|
4:op_writelong((dp << 16) | regs.y.w, rd.l);
|
||||||
|
5:op_io();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l $1;
|
||||||
|
regs.y.l $1;
|
||||||
|
} else {
|
||||||
|
regs.x.w $1;
|
||||||
|
regs.y.w $1;
|
||||||
|
}
|
||||||
|
6:last_cycle();
|
||||||
|
op_io();
|
||||||
|
if(regs.a.w--) regs.pc.w -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
brk(0x00, 0xfffe, 0xffff, 0xffe6, 0xffe7),
|
||||||
|
cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
|
||||||
|
1:op_readpc();
|
||||||
|
2:if(!regs.e) op_writestack(regs.pc.b);
|
||||||
|
3:op_writestack(regs.pc.h);
|
||||||
|
4:op_writestack(regs.pc.l);
|
||||||
|
5:op_writestack(regs.p);
|
||||||
|
6:rd.l = op_readlong(regs.e ? $1 : $3);
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
regs.p.i = 1;
|
||||||
|
regs.p.d = 0;
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readlong(regs.e ? $2 : $4);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
stp(0xdb) {
|
||||||
|
1:op_io();
|
||||||
|
2:last_cycle();
|
||||||
|
while(true) op_io();
|
||||||
|
}
|
||||||
|
|
||||||
|
wai(0xcb) {
|
||||||
|
//last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached
|
||||||
|
1:status.wai_lock = true;
|
||||||
|
while(status.wai_lock) {
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
2:op_io();
|
||||||
|
}
|
||||||
|
|
||||||
|
xce(0xfb) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
bool carry = regs.p.c;
|
||||||
|
regs.p.c = regs.e;
|
||||||
|
regs.e = carry;
|
||||||
|
if(regs.e) {
|
||||||
|
regs.p |= 0x30;
|
||||||
|
regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clc(0x18, regs.p.c = 0),
|
||||||
|
cld(0xd8, regs.p.d = 0),
|
||||||
|
cli(0x58, regs.p.i = 0),
|
||||||
|
clv(0xb8, regs.p.v = 0),
|
||||||
|
sec(0x38, regs.p.c = 1),
|
||||||
|
sed(0xf8, regs.p.d = 1),
|
||||||
|
sei(0x78, regs.p.i = 1) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
$1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rep(0xc2, &=~),
|
||||||
|
sep(0xe2, |=) {
|
||||||
|
1:rd.l = op_readpc();
|
||||||
|
2:last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.p $1 rd.l;
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tax(0xaa, regs.p.x, x, a),
|
||||||
|
tay(0xa8, regs.p.x, y, a),
|
||||||
|
txa(0x8a, regs.p.m, a, x),
|
||||||
|
txy(0x9b, regs.p.x, y, x),
|
||||||
|
tya(0x98, regs.p.m, a, y),
|
||||||
|
tyx(0xbb, regs.p.x, x, y) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if($1) {
|
||||||
|
regs.$2.l = regs.$3.l;
|
||||||
|
regs.p.n = !!(regs.$2.l & 0x80);
|
||||||
|
regs.p.z = (regs.$2.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.$2.w = regs.$3.w;
|
||||||
|
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||||
|
regs.p.z = (regs.$2.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcd(0x5b) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.d.w = regs.a.w;
|
||||||
|
regs.p.n = !!(regs.d.w & 0x8000);
|
||||||
|
regs.p.z = (regs.d.w == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcs(0x1b) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.s.w = regs.a.w;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdc(0x7b) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.a.w = regs.d.w;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tsc(0x3b) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.a.w = regs.s.w;
|
||||||
|
if(regs.e) {
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tsx(0xba) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l = regs.s.l;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w = regs.s.w;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
txs(0x9a) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.e) {
|
||||||
|
regs.s.l = regs.x.l;
|
||||||
|
} else {
|
||||||
|
regs.s.w = regs.x.w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pha(0x48, regs.p.m, a),
|
||||||
|
phx(0xda, regs.p.x, x),
|
||||||
|
phy(0x5a, regs.p.x, y) {
|
||||||
|
1:op_io();
|
||||||
|
2:if(!$1)op_writestack(regs.$2.h);
|
||||||
|
3:last_cycle();
|
||||||
|
op_writestack(regs.$2.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
phd(0x0b) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_writestackn(regs.d.h);
|
||||||
|
3:last_cycle();
|
||||||
|
op_writestackn(regs.d.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
phb(0x8b, regs.db),
|
||||||
|
phk(0x4b, regs.pc.b),
|
||||||
|
php(0x08, regs.p) {
|
||||||
|
1:op_io();
|
||||||
|
2:last_cycle();
|
||||||
|
op_writestack($1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pla(0x68, regs.p.m, a),
|
||||||
|
plx(0xfa, regs.p.x, x),
|
||||||
|
ply(0x7a, regs.p.x, y) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:if($1)last_cycle();
|
||||||
|
regs.$2.l = op_readstack();
|
||||||
|
if($1) {
|
||||||
|
regs.p.n = !!(regs.$2.l & 0x80);
|
||||||
|
regs.p.z = (regs.$2.l == 0);
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
4:last_cycle();
|
||||||
|
regs.$2.h = op_readstack();
|
||||||
|
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||||
|
regs.p.z = (regs.$2.w == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pld(0x2b) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:regs.d.l = op_readstackn();
|
||||||
|
4:last_cycle();
|
||||||
|
regs.d.h = op_readstackn();
|
||||||
|
regs.p.n = !!(regs.d.w & 0x8000);
|
||||||
|
regs.p.z = (regs.d.w == 0);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
plb(0xab) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:last_cycle();
|
||||||
|
regs.db = op_readstack();
|
||||||
|
regs.p.n = !!(regs.db & 0x80);
|
||||||
|
regs.p.z = (regs.db == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
plp(0x28) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:last_cycle();
|
||||||
|
regs.p = op_readstack();
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pea(0xf4) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_writestackn(aa.h);
|
||||||
|
4:last_cycle();
|
||||||
|
op_writestackn(aa.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
pei(0xd4) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:op_writestackn(aa.h);
|
||||||
|
6:last_cycle();
|
||||||
|
op_writestackn(aa.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
per(0x62) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
rd.w = regs.pc.d + (int16)aa.w;
|
||||||
|
4:op_writestackn(rd.h);
|
||||||
|
5:last_cycle();
|
||||||
|
op_writestackn(rd.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
539
bsnes/cpu/scpu/core/op_misc.cpp
Executable file
539
bsnes/cpu/scpu/core/op_misc.cpp
Executable file
@ -0,0 +1,539 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//nop
|
||||||
|
case 0xea: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//wdm
|
||||||
|
case 0x42: {
|
||||||
|
last_cycle();
|
||||||
|
op_readpc();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//xba
|
||||||
|
case 0xeb: {
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.a.l ^= regs.a.h;
|
||||||
|
regs.a.h ^= regs.a.l;
|
||||||
|
regs.a.l ^= regs.a.h;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//mvn
|
||||||
|
case 0x54: {
|
||||||
|
dp = op_readpc();
|
||||||
|
sp = op_readpc();
|
||||||
|
regs.db = dp;
|
||||||
|
rd.l = op_readlong((sp << 16) | regs.x.w);
|
||||||
|
op_writelong((dp << 16) | regs.y.w, rd.l);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l ++;
|
||||||
|
regs.y.l ++;
|
||||||
|
} else {
|
||||||
|
regs.x.w ++;
|
||||||
|
regs.y.w ++;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
if(regs.a.w--) regs.pc.w -= 3;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//mvp
|
||||||
|
case 0x44: {
|
||||||
|
dp = op_readpc();
|
||||||
|
sp = op_readpc();
|
||||||
|
regs.db = dp;
|
||||||
|
rd.l = op_readlong((sp << 16) | regs.x.w);
|
||||||
|
op_writelong((dp << 16) | regs.y.w, rd.l);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l --;
|
||||||
|
regs.y.l --;
|
||||||
|
} else {
|
||||||
|
regs.x.w --;
|
||||||
|
regs.y.w --;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
if(regs.a.w--) regs.pc.w -= 3;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//brk
|
||||||
|
case 0x00: {
|
||||||
|
op_readpc();
|
||||||
|
if(!regs.e) op_writestack(regs.pc.b);
|
||||||
|
op_writestack(regs.pc.h);
|
||||||
|
op_writestack(regs.pc.l);
|
||||||
|
op_writestack(regs.p);
|
||||||
|
rd.l = op_readlong(regs.e ? 0xfffe : 0xffe6);
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
regs.p.i = 1;
|
||||||
|
regs.p.d = 0;
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readlong(regs.e ? 0xffff : 0xffe7);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//cop
|
||||||
|
case 0x02: {
|
||||||
|
op_readpc();
|
||||||
|
if(!regs.e) op_writestack(regs.pc.b);
|
||||||
|
op_writestack(regs.pc.h);
|
||||||
|
op_writestack(regs.pc.l);
|
||||||
|
op_writestack(regs.p);
|
||||||
|
rd.l = op_readlong(regs.e ? 0xfff4 : 0xffe4);
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
regs.p.i = 1;
|
||||||
|
regs.p.d = 0;
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readlong(regs.e ? 0xfff5 : 0xffe5);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stp
|
||||||
|
case 0xdb: {
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
while(true) op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//wai
|
||||||
|
case 0xcb: {
|
||||||
|
//last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached
|
||||||
|
status.wai_lock = true;
|
||||||
|
while(status.wai_lock) {
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//xce
|
||||||
|
case 0xfb: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
bool carry = regs.p.c;
|
||||||
|
regs.p.c = regs.e;
|
||||||
|
regs.e = carry;
|
||||||
|
if(regs.e) {
|
||||||
|
regs.p |= 0x30;
|
||||||
|
regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//clc
|
||||||
|
case 0x18: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.c = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//cld
|
||||||
|
case 0xd8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.d = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//cli
|
||||||
|
case 0x58: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.i = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//clv
|
||||||
|
case 0xb8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.v = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sec
|
||||||
|
case 0x38: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.c = 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sed
|
||||||
|
case 0xf8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.d = 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sei
|
||||||
|
case 0x78: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.p.i = 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rep
|
||||||
|
case 0xc2: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.p &=~ rd.l;
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sep
|
||||||
|
case 0xe2: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.p |= rd.l;
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tax
|
||||||
|
case 0xaa: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l = regs.a.l;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w = regs.a.w;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tay
|
||||||
|
case 0xa8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.y.l = regs.a.l;
|
||||||
|
regs.p.n = !!(regs.y.l & 0x80);
|
||||||
|
regs.p.z = (regs.y.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.y.w = regs.a.w;
|
||||||
|
regs.p.n = !!(regs.y.w & 0x8000);
|
||||||
|
regs.p.z = (regs.y.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//txa
|
||||||
|
case 0x8a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.a.l = regs.x.l;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.a.w = regs.x.w;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//txy
|
||||||
|
case 0x9b: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.y.l = regs.x.l;
|
||||||
|
regs.p.n = !!(regs.y.l & 0x80);
|
||||||
|
regs.p.z = (regs.y.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.y.w = regs.x.w;
|
||||||
|
regs.p.n = !!(regs.y.w & 0x8000);
|
||||||
|
regs.p.z = (regs.y.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tya
|
||||||
|
case 0x98: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.a.l = regs.y.l;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.a.w = regs.y.w;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tyx
|
||||||
|
case 0xbb: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l = regs.y.l;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w = regs.y.w;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tcd
|
||||||
|
case 0x5b: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.d.w = regs.a.w;
|
||||||
|
regs.p.n = !!(regs.d.w & 0x8000);
|
||||||
|
regs.p.z = (regs.d.w == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tcs
|
||||||
|
case 0x1b: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.s.w = regs.a.w;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tdc
|
||||||
|
case 0x7b: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.a.w = regs.d.w;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tsc
|
||||||
|
case 0x3b: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
regs.a.w = regs.s.w;
|
||||||
|
if(regs.e) {
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tsx
|
||||||
|
case 0xba: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l = regs.s.l;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w = regs.s.w;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//txs
|
||||||
|
case 0x9a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.e) {
|
||||||
|
regs.s.l = regs.x.l;
|
||||||
|
} else {
|
||||||
|
regs.s.w = regs.x.w;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//pha
|
||||||
|
case 0x48: {
|
||||||
|
op_io();
|
||||||
|
if(!regs.p.m)op_writestack(regs.a.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.a.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//phx
|
||||||
|
case 0xda: {
|
||||||
|
op_io();
|
||||||
|
if(!regs.p.x)op_writestack(regs.x.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.x.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//phy
|
||||||
|
case 0x5a: {
|
||||||
|
op_io();
|
||||||
|
if(!regs.p.x)op_writestack(regs.y.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.y.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//phd
|
||||||
|
case 0x0b: {
|
||||||
|
op_io();
|
||||||
|
op_writestackn(regs.d.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestackn(regs.d.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//phb
|
||||||
|
case 0x8b: {
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.db);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//phk
|
||||||
|
case 0x4b: {
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.pc.b);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//php
|
||||||
|
case 0x08: {
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.p);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//pla
|
||||||
|
case 0x68: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m)last_cycle();
|
||||||
|
regs.a.l = op_readstack();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
regs.a.h = op_readstack();
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//plx
|
||||||
|
case 0xfa: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x)last_cycle();
|
||||||
|
regs.x.l = op_readstack();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
regs.x.h = op_readstack();
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ply
|
||||||
|
case 0x7a: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x)last_cycle();
|
||||||
|
regs.y.l = op_readstack();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.p.n = !!(regs.y.l & 0x80);
|
||||||
|
regs.p.z = (regs.y.l == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
regs.y.h = op_readstack();
|
||||||
|
regs.p.n = !!(regs.y.w & 0x8000);
|
||||||
|
regs.p.z = (regs.y.w == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//pld
|
||||||
|
case 0x2b: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
regs.d.l = op_readstackn();
|
||||||
|
last_cycle();
|
||||||
|
regs.d.h = op_readstackn();
|
||||||
|
regs.p.n = !!(regs.d.w & 0x8000);
|
||||||
|
regs.p.z = (regs.d.w == 0);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//plb
|
||||||
|
case 0xab: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
regs.db = op_readstack();
|
||||||
|
regs.p.n = !!(regs.db & 0x80);
|
||||||
|
regs.p.z = (regs.db == 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//plp
|
||||||
|
case 0x28: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
last_cycle();
|
||||||
|
regs.p = op_readstack();
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//pea
|
||||||
|
case 0xf4: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_writestackn(aa.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestackn(aa.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//pei
|
||||||
|
case 0xd4: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
aa.l = op_readdp(dp);
|
||||||
|
aa.h = op_readdp(dp + 1);
|
||||||
|
op_writestackn(aa.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestackn(aa.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//per
|
||||||
|
case 0x62: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.w = regs.pc.d + (int16)aa.w;
|
||||||
|
op_writestackn(rd.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestackn(rd.l);
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
#endif
|
||||||
163
bsnes/cpu/scpu/core/op_pc.b
Executable file
163
bsnes/cpu/scpu/core/op_pc.b
Executable file
@ -0,0 +1,163 @@
|
|||||||
|
bcc(0x90, !regs.p.c),
|
||||||
|
bcs(0xb0, regs.p.c),
|
||||||
|
bne(0xd0, !regs.p.z),
|
||||||
|
beq(0xf0, regs.p.z),
|
||||||
|
bpl(0x10, !regs.p.n),
|
||||||
|
bmi(0x30, regs.p.n),
|
||||||
|
bvc(0x50, !regs.p.v),
|
||||||
|
bvs(0x70, regs.p.v) {
|
||||||
|
1:if(!$1) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if($1) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
2:op_io_cond6(aa.w);
|
||||||
|
3:last_cycle();
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
|
||||||
|
bra(0x80) {
|
||||||
|
1:rd.l = op_readpc();
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
2:op_io_cond6(aa.w);
|
||||||
|
3:last_cycle();
|
||||||
|
op_io();
|
||||||
|
}
|
||||||
|
|
||||||
|
brl(0x82) {
|
||||||
|
1:rd.l = op_readpc();
|
||||||
|
2:rd.h = op_readpc();
|
||||||
|
3:last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp_addr(0x4c) {
|
||||||
|
1:rd.l = op_readpc();
|
||||||
|
2:last_cycle();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp_long(0x5c) {
|
||||||
|
1:rd.l = op_readpc();
|
||||||
|
2:rd.h = op_readpc();
|
||||||
|
3:last_cycle();
|
||||||
|
rd.b = op_readpc();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp_iaddr(0x6c) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:rd.l = op_readaddr(aa.w);
|
||||||
|
4:last_cycle();
|
||||||
|
rd.h = op_readaddr(aa.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp_iaddrx(0x7c) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
4:rd.l = op_readpbr(aa.w + regs.x.w);
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp_iladdr(0xdc) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:rd.l = op_readaddr(aa.w);
|
||||||
|
4:rd.h = op_readaddr(aa.w + 1);
|
||||||
|
5:last_cycle();
|
||||||
|
rd.b = op_readaddr(aa.w + 2);
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsr_addr(0x20) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
4:regs.pc.w--;
|
||||||
|
op_writestack(regs.pc.h);
|
||||||
|
5:last_cycle();
|
||||||
|
op_writestack(regs.pc.l);
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsr_long(0x22) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_writestackn(regs.pc.b);
|
||||||
|
4:op_io();
|
||||||
|
5:aa.b = op_readpc();
|
||||||
|
6:regs.pc.w--;
|
||||||
|
op_writestackn(regs.pc.h);
|
||||||
|
7:last_cycle();
|
||||||
|
op_writestackn(regs.pc.l);
|
||||||
|
regs.pc.d = aa.d & 0xffffff;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsr_iaddrx(0xfc) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:op_writestackn(regs.pc.h);
|
||||||
|
3:op_writestackn(regs.pc.l);
|
||||||
|
4:aa.h = op_readpc();
|
||||||
|
5:op_io();
|
||||||
|
6:rd.l = op_readpbr(aa.w + regs.x.w);
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
rti(0x40) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:regs.p = op_readstack();
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
4:rd.l = op_readstack();
|
||||||
|
5:if(regs.e) last_cycle();
|
||||||
|
rd.h = op_readstack();
|
||||||
|
if(regs.e) {
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
6:last_cycle();
|
||||||
|
rd.b = op_readstack();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
rts(0x60) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:rd.l = op_readstack();
|
||||||
|
4:rd.h = op_readstack();
|
||||||
|
5:last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
regs.pc.w++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtl(0x6b) {
|
||||||
|
1:op_io();
|
||||||
|
2:op_io();
|
||||||
|
3:rd.l = op_readstackn();
|
||||||
|
4:rd.h = op_readstackn();
|
||||||
|
5:last_cycle();
|
||||||
|
rd.b = op_readstackn();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
regs.pc.w++;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
}
|
||||||
279
bsnes/cpu/scpu/core/op_pc.cpp
Executable file
279
bsnes/cpu/scpu/core/op_pc.cpp
Executable file
@ -0,0 +1,279 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//bcc
|
||||||
|
case 0x90: {
|
||||||
|
if(!!regs.p.c) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(!regs.p.c) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bcs
|
||||||
|
case 0xb0: {
|
||||||
|
if(!regs.p.c) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(regs.p.c) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bne
|
||||||
|
case 0xd0: {
|
||||||
|
if(!!regs.p.z) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(!regs.p.z) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//beq
|
||||||
|
case 0xf0: {
|
||||||
|
if(!regs.p.z) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(regs.p.z) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bpl
|
||||||
|
case 0x10: {
|
||||||
|
if(!!regs.p.n) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(!regs.p.n) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bmi
|
||||||
|
case 0x30: {
|
||||||
|
if(!regs.p.n) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(regs.p.n) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bvc
|
||||||
|
case 0x50: {
|
||||||
|
if(!!regs.p.v) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(!regs.p.v) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bvs
|
||||||
|
case 0x70: {
|
||||||
|
if(!regs.p.v) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(regs.p.v) {
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//bra
|
||||||
|
case 0x80: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
aa.w = regs.pc.d + (int8)rd.l;
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
op_io_cond6(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//brl
|
||||||
|
case 0x82: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.pc.w = regs.pc.d + (int16)rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jmp_addr
|
||||||
|
case 0x4c: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jmp_long
|
||||||
|
case 0x5c: {
|
||||||
|
rd.l = op_readpc();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
last_cycle();
|
||||||
|
rd.b = op_readpc();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jmp_iaddr
|
||||||
|
case 0x6c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readaddr(aa.w);
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readaddr(aa.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jmp_iaddrx
|
||||||
|
case 0x7c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readpbr(aa.w + regs.x.w);
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jmp_iladdr
|
||||||
|
case 0xdc: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readaddr(aa.w);
|
||||||
|
rd.h = op_readaddr(aa.w + 1);
|
||||||
|
last_cycle();
|
||||||
|
rd.b = op_readaddr(aa.w + 2);
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jsr_addr
|
||||||
|
case 0x20: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
regs.pc.w--;
|
||||||
|
op_writestack(regs.pc.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestack(regs.pc.l);
|
||||||
|
regs.pc.w = aa.w;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jsr_long
|
||||||
|
case 0x22: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_writestackn(regs.pc.b);
|
||||||
|
op_io();
|
||||||
|
aa.b = op_readpc();
|
||||||
|
regs.pc.w--;
|
||||||
|
op_writestackn(regs.pc.h);
|
||||||
|
last_cycle();
|
||||||
|
op_writestackn(regs.pc.l);
|
||||||
|
regs.pc.d = aa.d & 0xffffff;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//jsr_iaddrx
|
||||||
|
case 0xfc: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
op_writestackn(regs.pc.h);
|
||||||
|
op_writestackn(regs.pc.l);
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readpbr(aa.w + regs.x.w);
|
||||||
|
last_cycle();
|
||||||
|
rd.h = op_readpbr(aa.w + regs.x.w + 1);
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rti
|
||||||
|
case 0x40: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
regs.p = op_readstack();
|
||||||
|
if(regs.e) regs.p |= 0x30;
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
}
|
||||||
|
rd.l = op_readstack();
|
||||||
|
if(regs.e) last_cycle();
|
||||||
|
rd.h = op_readstack();
|
||||||
|
if(regs.e) {
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_cycle();
|
||||||
|
rd.b = op_readstack();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rts
|
||||||
|
case 0x60: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readstack();
|
||||||
|
rd.h = op_readstack();
|
||||||
|
last_cycle();
|
||||||
|
op_io();
|
||||||
|
regs.pc.w = rd.w;
|
||||||
|
regs.pc.w++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
case 0x6b: {
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readstackn();
|
||||||
|
rd.h = op_readstackn();
|
||||||
|
last_cycle();
|
||||||
|
rd.b = op_readstackn();
|
||||||
|
regs.pc.d = rd.d & 0xffffff;
|
||||||
|
regs.pc.w++;
|
||||||
|
if(regs.e) regs.s.h = 0x01;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
#endif
|
||||||
317
bsnes/cpu/scpu/core/op_read.b
Executable file
317
bsnes/cpu/scpu/core/op_read.b
Executable file
@ -0,0 +1,317 @@
|
|||||||
|
adc_const(0x69, adc, regs.p.m),
|
||||||
|
and_const(0x29, and, regs.p.m),
|
||||||
|
cmp_const(0xc9, cmp, regs.p.m),
|
||||||
|
cpx_const(0xe0, cpx, regs.p.x),
|
||||||
|
cpy_const(0xc0, cpy, regs.p.x),
|
||||||
|
eor_const(0x49, eor, regs.p.m),
|
||||||
|
lda_const(0xa9, lda, regs.p.m),
|
||||||
|
ldx_const(0xa2, ldx, regs.p.x),
|
||||||
|
ldy_const(0xa0, ldy, regs.p.x),
|
||||||
|
ora_const(0x09, ora, regs.p.m),
|
||||||
|
sbc_const(0xe9, sbc, regs.p.m) {
|
||||||
|
1:if($2) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
2:last_cycle();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_addr(0x6d, adc, regs.p.m),
|
||||||
|
and_addr(0x2d, and, regs.p.m),
|
||||||
|
bit_addr(0x2c, bit, regs.p.m),
|
||||||
|
cmp_addr(0xcd, cmp, regs.p.m),
|
||||||
|
cpx_addr(0xec, cpx, regs.p.x),
|
||||||
|
cpy_addr(0xcc, cpy, regs.p.x),
|
||||||
|
eor_addr(0x4d, eor, regs.p.m),
|
||||||
|
lda_addr(0xad, lda, regs.p.m),
|
||||||
|
ldx_addr(0xae, ldx, regs.p.x),
|
||||||
|
ldy_addr(0xac, ldy, regs.p.x),
|
||||||
|
ora_addr(0x0d, ora, regs.p.m),
|
||||||
|
sbc_addr(0xed, sbc, regs.p.m) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
4:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_addrx(0x7d, adc, regs.p.m),
|
||||||
|
and_addrx(0x3d, and, regs.p.m),
|
||||||
|
bit_addrx(0x3c, bit, regs.p.m),
|
||||||
|
cmp_addrx(0xdd, cmp, regs.p.m),
|
||||||
|
eor_addrx(0x5d, eor, regs.p.m),
|
||||||
|
lda_addrx(0xbd, lda, regs.p.m),
|
||||||
|
ldy_addrx(0xbc, ldy, regs.p.x),
|
||||||
|
ora_addrx(0x1d, ora, regs.p.m),
|
||||||
|
sbc_addrx(0xfd, sbc, regs.p.m) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io_cond4(aa.w, aa.w + regs.x.w);
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_addry(0x79, adc, regs.p.m),
|
||||||
|
and_addry(0x39, and, regs.p.m),
|
||||||
|
cmp_addry(0xd9, cmp, regs.p.m),
|
||||||
|
eor_addry(0x59, eor, regs.p.m),
|
||||||
|
lda_addry(0xb9, lda, regs.p.m),
|
||||||
|
ldx_addry(0xbe, ldx, regs.p.x),
|
||||||
|
ora_addry(0x19, ora, regs.p.m),
|
||||||
|
sbc_addry(0xf9, sbc, regs.p.m) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.y.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + regs.y.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_long(0x6f, adc, regs.p.m),
|
||||||
|
and_long(0x2f, and, regs.p.m),
|
||||||
|
cmp_long(0xcf, cmp, regs.p.m),
|
||||||
|
eor_long(0x4f, eor, regs.p.m),
|
||||||
|
lda_long(0xaf, lda, regs.p.m),
|
||||||
|
ora_long(0x0f, ora, regs.p.m),
|
||||||
|
sbc_long(0xef, sbc, regs.p.m) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:aa.b = op_readpc();
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readlong(aa.d);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readlong(aa.d + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_longx(0x7f, adc, regs.p.m),
|
||||||
|
and_longx(0x3f, and, regs.p.m),
|
||||||
|
cmp_longx(0xdf, cmp, regs.p.m),
|
||||||
|
eor_longx(0x5f, eor, regs.p.m),
|
||||||
|
lda_longx(0xbf, lda, regs.p.m),
|
||||||
|
ora_longx(0x1f, ora, regs.p.m),
|
||||||
|
sbc_longx(0xff, sbc, regs.p.m) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:aa.b = op_readpc();
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readlong(aa.d + regs.x.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readlong(aa.d + regs.x.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_dp(0x65, adc, regs.p.m),
|
||||||
|
and_dp(0x25, and, regs.p.m),
|
||||||
|
bit_dp(0x24, bit, regs.p.m),
|
||||||
|
cmp_dp(0xc5, cmp, regs.p.m),
|
||||||
|
cpx_dp(0xe4, cpx, regs.p.x),
|
||||||
|
cpy_dp(0xc4, cpy, regs.p.x),
|
||||||
|
eor_dp(0x45, eor, regs.p.m),
|
||||||
|
lda_dp(0xa5, lda, regs.p.m),
|
||||||
|
ldx_dp(0xa6, ldx, regs.p.x),
|
||||||
|
ldy_dp(0xa4, ldy, regs.p.x),
|
||||||
|
ora_dp(0x05, ora, regs.p.m),
|
||||||
|
sbc_dp(0xe5, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:if($2) last_cycle();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
4:last_cycle();
|
||||||
|
rd.h = op_readdp(dp + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_dpx(0x75, adc, regs.p.m),
|
||||||
|
and_dpx(0x35, and, regs.p.m),
|
||||||
|
bit_dpx(0x34, bit, regs.p.m),
|
||||||
|
cmp_dpx(0xd5, cmp, regs.p.m),
|
||||||
|
eor_dpx(0x55, eor, regs.p.m),
|
||||||
|
lda_dpx(0xb5, lda, regs.p.m),
|
||||||
|
ldy_dpx(0xb4, ldy, regs.p.x),
|
||||||
|
ora_dpx(0x15, ora, regs.p.m),
|
||||||
|
sbc_dpx(0xf5, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
ldx_dpy(0xb6, ldx, regs.p.x) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:if($2) last_cycle();
|
||||||
|
rd.l = op_readdp(dp + regs.y.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
5:last_cycle();
|
||||||
|
rd.h = op_readdp(dp + regs.y.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_idp(0x72, adc, regs.p.m),
|
||||||
|
and_idp(0x32, and, regs.p.m),
|
||||||
|
cmp_idp(0xd2, cmp, regs.p.m),
|
||||||
|
eor_idp(0x52, eor, regs.p.m),
|
||||||
|
lda_idp(0xb2, lda, regs.p.m),
|
||||||
|
ora_idp(0x12, ora, regs.p.m),
|
||||||
|
sbc_idp(0xf2, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
6:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_idpx(0x61, adc, regs.p.m),
|
||||||
|
and_idpx(0x21, and, regs.p.m),
|
||||||
|
cmp_idpx(0xc1, cmp, regs.p.m),
|
||||||
|
eor_idpx(0x41, eor, regs.p.m),
|
||||||
|
lda_idpx(0xa1, lda, regs.p.m),
|
||||||
|
ora_idpx(0x01, ora, regs.p.m),
|
||||||
|
sbc_idpx(0xe1, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:aa.l = op_readdp(dp + regs.x.w);
|
||||||
|
5:aa.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
6:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_idpy(0x71, adc, regs.p.m),
|
||||||
|
and_idpy(0x31, and, regs.p.m),
|
||||||
|
cmp_idpy(0xd1, cmp, regs.p.m),
|
||||||
|
eor_idpy(0x51, eor, regs.p.m),
|
||||||
|
lda_idpy(0xb1, lda, regs.p.m),
|
||||||
|
ora_idpy(0x11, ora, regs.p.m),
|
||||||
|
sbc_idpy(0xf1, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:op_io_cond4(aa.w, aa.w + regs.y.w);
|
||||||
|
6:if($2) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.y.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + regs.y.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_ildp(0x67, adc, regs.p.m),
|
||||||
|
and_ildp(0x27, and, regs.p.m),
|
||||||
|
cmp_ildp(0xc7, cmp, regs.p.m),
|
||||||
|
eor_ildp(0x47, eor, regs.p.m),
|
||||||
|
lda_ildp(0xa7, lda, regs.p.m),
|
||||||
|
ora_ildp(0x07, ora, regs.p.m),
|
||||||
|
sbc_ildp(0xe7, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:aa.b = op_readdp(dp + 2);
|
||||||
|
6:if($2) last_cycle();
|
||||||
|
rd.l = op_readlong(aa.d);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readlong(aa.d + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_ildpy(0x77, adc, regs.p.m),
|
||||||
|
and_ildpy(0x37, and, regs.p.m),
|
||||||
|
cmp_ildpy(0xd7, cmp, regs.p.m),
|
||||||
|
eor_ildpy(0x57, eor, regs.p.m),
|
||||||
|
lda_ildpy(0xb7, lda, regs.p.m),
|
||||||
|
ora_ildpy(0x17, ora, regs.p.m),
|
||||||
|
sbc_ildpy(0xf7, sbc, regs.p.m) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:aa.b = op_readdp(dp + 2);
|
||||||
|
6:if($2) last_cycle();
|
||||||
|
rd.l = op_readlong(aa.d + regs.y.w);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readlong(aa.d + regs.y.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_sr(0x63, adc, regs.p.m),
|
||||||
|
and_sr(0x23, and, regs.p.m),
|
||||||
|
cmp_sr(0xc3, cmp, regs.p.m),
|
||||||
|
eor_sr(0x43, eor, regs.p.m),
|
||||||
|
lda_sr(0xa3, lda, regs.p.m),
|
||||||
|
ora_sr(0x03, ora, regs.p.m),
|
||||||
|
sbc_sr(0xe3, sbc, regs.p.m) {
|
||||||
|
1:sp = op_readpc();
|
||||||
|
2:op_io();
|
||||||
|
3:if($2) last_cycle();
|
||||||
|
rd.l = op_readsp(sp);
|
||||||
|
if($2) { op_$1_b(); end; }
|
||||||
|
4:last_cycle();
|
||||||
|
rd.h = op_readsp(sp + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_isry(0x73, adc),
|
||||||
|
and_isry(0x33, and),
|
||||||
|
cmp_isry(0xd3, cmp),
|
||||||
|
eor_isry(0x53, eor),
|
||||||
|
lda_isry(0xb3, lda),
|
||||||
|
ora_isry(0x13, ora),
|
||||||
|
sbc_isry(0xf3, sbc) {
|
||||||
|
1:sp = op_readpc();
|
||||||
|
2:op_io();
|
||||||
|
3:aa.l = op_readsp(sp);
|
||||||
|
4:aa.h = op_readsp(sp + 1);
|
||||||
|
5:op_io();
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.y.w);
|
||||||
|
if(regs.p.m) { op_$1_b(); end; }
|
||||||
|
7:last_cycle();
|
||||||
|
rd.h = op_readdbr(aa.w + regs.y.w + 1);
|
||||||
|
op_$1_w();
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_const(0x89) {
|
||||||
|
1:if(regs.p.m) last_cycle();
|
||||||
|
rd.l = op_readpc();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.z = ((rd.l & regs.a.l) == 0);
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
2:last_cycle();
|
||||||
|
rd.h = op_readpc();
|
||||||
|
regs.p.z = ((rd.w & regs.a.w) == 0);
|
||||||
|
}
|
||||||
1654
bsnes/cpu/scpu/core/op_read.cpp
Executable file
1654
bsnes/cpu/scpu/core/op_read.cpp
Executable file
File diff suppressed because it is too large
Load Diff
181
bsnes/cpu/scpu/core/op_rmw.b
Executable file
181
bsnes/cpu/scpu/core/op_rmw.b
Executable file
@ -0,0 +1,181 @@
|
|||||||
|
inc(0x1a, regs.p.m, a),
|
||||||
|
inx(0xe8, regs.p.x, x),
|
||||||
|
iny(0xc8, regs.p.x, y) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if($1) {
|
||||||
|
regs.$2.l++;
|
||||||
|
regs.p.n = !!(regs.$2.l & 0x80);
|
||||||
|
regs.p.z = (regs.$2.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.$2.w++;
|
||||||
|
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||||
|
regs.p.z = (regs.$2.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dec(0x3a, regs.p.m, a),
|
||||||
|
dex(0xca, regs.p.x, x),
|
||||||
|
dey(0x88, regs.p.x, y) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if($1) {
|
||||||
|
regs.$2.l--;
|
||||||
|
regs.p.n = !!(regs.$2.l & 0x80);
|
||||||
|
regs.p.z = (regs.$2.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.$2.w--;
|
||||||
|
regs.p.n = !!(regs.$2.w & 0x8000);
|
||||||
|
regs.p.z = (regs.$2.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
asl(0x0a) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = !!(regs.a.l & 0x80);
|
||||||
|
regs.a.l <<= 1;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = !!(regs.a.w & 0x8000);
|
||||||
|
regs.a.w <<= 1;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lsr(0x4a) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = regs.a.l & 1;
|
||||||
|
regs.a.l >>= 1;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = regs.a.w & 1;
|
||||||
|
regs.a.w >>= 1;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rol(0x2a) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
uint16 c = regs.p.c;
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = !!(regs.a.l & 0x80);
|
||||||
|
regs.a.l <<= 1;
|
||||||
|
regs.a.l |= c;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = !!(regs.a.w & 0x8000);
|
||||||
|
regs.a.w <<= 1;
|
||||||
|
regs.a.w |= c;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ror(0x6a) {
|
||||||
|
1:last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
uint16 c;
|
||||||
|
if(regs.p.m) {
|
||||||
|
c = regs.p.c ? 0x80 : 0;
|
||||||
|
regs.p.c = regs.a.l & 1;
|
||||||
|
regs.a.l >>= 1;
|
||||||
|
regs.a.l |= c;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
c = regs.p.c ? 0x8000 : 0;
|
||||||
|
regs.p.c = regs.a.w & 1;
|
||||||
|
regs.a.w >>= 1;
|
||||||
|
regs.a.w |= c;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_addr(0xee, inc),
|
||||||
|
dec_addr(0xce, dec),
|
||||||
|
asl_addr(0x0e, asl),
|
||||||
|
lsr_addr(0x4e, lsr),
|
||||||
|
rol_addr(0x2e, rol),
|
||||||
|
ror_addr(0x6e, ror),
|
||||||
|
trb_addr(0x1c, trb),
|
||||||
|
tsb_addr(0x0c, tsb) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:rd.l = op_readdbr(aa.w);
|
||||||
|
4:if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
5:op_io();
|
||||||
|
if(regs.p.m) { op_$1_b(); }
|
||||||
|
else { op_$1_w();
|
||||||
|
6:op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
7:last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_addrx(0xfe, inc),
|
||||||
|
dec_addrx(0xde, dec),
|
||||||
|
asl_addrx(0x1e, asl),
|
||||||
|
lsr_addrx(0x5e, lsr),
|
||||||
|
rol_addrx(0x3e, rol),
|
||||||
|
ror_addrx(0x7e, ror) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
4:rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
5:if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
6:op_io();
|
||||||
|
if(regs.p.m) { op_$1_b(); }
|
||||||
|
else { op_$1_w();
|
||||||
|
7:op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
8:last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_dp(0xe6, inc),
|
||||||
|
dec_dp(0xc6, dec),
|
||||||
|
asl_dp(0x06, asl),
|
||||||
|
lsr_dp(0x46, lsr),
|
||||||
|
rol_dp(0x26, rol),
|
||||||
|
ror_dp(0x66, ror),
|
||||||
|
trb_dp(0x14, trb),
|
||||||
|
tsb_dp(0x04, tsb) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:rd.l = op_readdp(dp);
|
||||||
|
4:if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
5:op_io();
|
||||||
|
if(regs.p.m) { op_$1_b(); }
|
||||||
|
else { op_$1_w();
|
||||||
|
6:op_writedp(dp + 1, rd.h); }
|
||||||
|
7:last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_dpx(0xf6, inc),
|
||||||
|
dec_dpx(0xd6, dec),
|
||||||
|
asl_dpx(0x16, asl),
|
||||||
|
lsr_dpx(0x56, lsr),
|
||||||
|
rol_dpx(0x36, rol),
|
||||||
|
ror_dpx(0x76, ror) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
5:if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
6:op_io();
|
||||||
|
if(regs.p.m) { op_$1_b(); }
|
||||||
|
else { op_$1_w();
|
||||||
|
7:op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
8:last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
}
|
||||||
573
bsnes/cpu/scpu/core/op_rmw.cpp
Executable file
573
bsnes/cpu/scpu/core/op_rmw.cpp
Executable file
@ -0,0 +1,573 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//inc
|
||||||
|
case 0x1a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.a.l++;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.a.w++;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//inx
|
||||||
|
case 0xe8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l++;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w++;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//iny
|
||||||
|
case 0xc8: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.y.l++;
|
||||||
|
regs.p.n = !!(regs.y.l & 0x80);
|
||||||
|
regs.p.z = (regs.y.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.y.w++;
|
||||||
|
regs.p.n = !!(regs.y.w & 0x8000);
|
||||||
|
regs.p.z = (regs.y.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dec
|
||||||
|
case 0x3a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.a.l--;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.a.w--;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dex
|
||||||
|
case 0xca: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.x.l--;
|
||||||
|
regs.p.n = !!(regs.x.l & 0x80);
|
||||||
|
regs.p.z = (regs.x.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.x.w--;
|
||||||
|
regs.p.n = !!(regs.x.w & 0x8000);
|
||||||
|
regs.p.z = (regs.x.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dey
|
||||||
|
case 0x88: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.x) {
|
||||||
|
regs.y.l--;
|
||||||
|
regs.p.n = !!(regs.y.l & 0x80);
|
||||||
|
regs.p.z = (regs.y.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.y.w--;
|
||||||
|
regs.p.n = !!(regs.y.w & 0x8000);
|
||||||
|
regs.p.z = (regs.y.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//asl
|
||||||
|
case 0x0a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = !!(regs.a.l & 0x80);
|
||||||
|
regs.a.l <<= 1;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = !!(regs.a.w & 0x8000);
|
||||||
|
regs.a.w <<= 1;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//lsr
|
||||||
|
case 0x4a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = regs.a.l & 1;
|
||||||
|
regs.a.l >>= 1;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = regs.a.w & 1;
|
||||||
|
regs.a.w >>= 1;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rol
|
||||||
|
case 0x2a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
uint16 c = regs.p.c;
|
||||||
|
if(regs.p.m) {
|
||||||
|
regs.p.c = !!(regs.a.l & 0x80);
|
||||||
|
regs.a.l <<= 1;
|
||||||
|
regs.a.l |= c;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
regs.p.c = !!(regs.a.w & 0x8000);
|
||||||
|
regs.a.w <<= 1;
|
||||||
|
regs.a.w |= c;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ror
|
||||||
|
case 0x6a: {
|
||||||
|
last_cycle();
|
||||||
|
op_io_irq();
|
||||||
|
uint16 c;
|
||||||
|
if(regs.p.m) {
|
||||||
|
c = regs.p.c ? 0x80 : 0;
|
||||||
|
regs.p.c = regs.a.l & 1;
|
||||||
|
regs.a.l >>= 1;
|
||||||
|
regs.a.l |= c;
|
||||||
|
regs.p.n = !!(regs.a.l & 0x80);
|
||||||
|
regs.p.z = (regs.a.l == 0);
|
||||||
|
} else {
|
||||||
|
c = regs.p.c ? 0x8000 : 0;
|
||||||
|
regs.p.c = regs.a.w & 1;
|
||||||
|
regs.a.w >>= 1;
|
||||||
|
regs.a.w |= c;
|
||||||
|
regs.p.n = !!(regs.a.w & 0x8000);
|
||||||
|
regs.p.z = (regs.a.w == 0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//inc_addr
|
||||||
|
case 0xee: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_inc_b(); }
|
||||||
|
else { op_inc_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dec_addr
|
||||||
|
case 0xce: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_dec_b(); }
|
||||||
|
else { op_dec_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//asl_addr
|
||||||
|
case 0x0e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_asl_b(); }
|
||||||
|
else { op_asl_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//lsr_addr
|
||||||
|
case 0x4e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_lsr_b(); }
|
||||||
|
else { op_lsr_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rol_addr
|
||||||
|
case 0x2e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_rol_b(); }
|
||||||
|
else { op_rol_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ror_addr
|
||||||
|
case 0x6e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_ror_b(); }
|
||||||
|
else { op_ror_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//trb_addr
|
||||||
|
case 0x1c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_trb_b(); }
|
||||||
|
else { op_trb_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tsb_addr
|
||||||
|
case 0x0c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
rd.l = op_readdbr(aa.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_tsb_b(); }
|
||||||
|
else { op_tsb_w();
|
||||||
|
op_writedbr(aa.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//inc_addrx
|
||||||
|
case 0xfe: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_inc_b(); }
|
||||||
|
else { op_inc_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dec_addrx
|
||||||
|
case 0xde: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_dec_b(); }
|
||||||
|
else { op_dec_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//asl_addrx
|
||||||
|
case 0x1e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_asl_b(); }
|
||||||
|
else { op_asl_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//lsr_addrx
|
||||||
|
case 0x5e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_lsr_b(); }
|
||||||
|
else { op_lsr_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rol_addrx
|
||||||
|
case 0x3e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_rol_b(); }
|
||||||
|
else { op_rol_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ror_addrx
|
||||||
|
case 0x7e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdbr(aa.w + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdbr(aa.w + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_ror_b(); }
|
||||||
|
else { op_ror_w();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//inc_dp
|
||||||
|
case 0xe6: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_inc_b(); }
|
||||||
|
else { op_inc_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dec_dp
|
||||||
|
case 0xc6: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_dec_b(); }
|
||||||
|
else { op_dec_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//asl_dp
|
||||||
|
case 0x06: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_asl_b(); }
|
||||||
|
else { op_asl_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//lsr_dp
|
||||||
|
case 0x46: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_lsr_b(); }
|
||||||
|
else { op_lsr_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rol_dp
|
||||||
|
case 0x26: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_rol_b(); }
|
||||||
|
else { op_rol_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ror_dp
|
||||||
|
case 0x66: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_ror_b(); }
|
||||||
|
else { op_ror_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//trb_dp
|
||||||
|
case 0x14: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_trb_b(); }
|
||||||
|
else { op_trb_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//tsb_dp
|
||||||
|
case 0x04: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
rd.l = op_readdp(dp);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_tsb_b(); }
|
||||||
|
else { op_tsb_w();
|
||||||
|
op_writedp(dp + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//inc_dpx
|
||||||
|
case 0xf6: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_inc_b(); }
|
||||||
|
else { op_inc_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//dec_dpx
|
||||||
|
case 0xd6: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_dec_b(); }
|
||||||
|
else { op_dec_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//asl_dpx
|
||||||
|
case 0x16: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_asl_b(); }
|
||||||
|
else { op_asl_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//lsr_dpx
|
||||||
|
case 0x56: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_lsr_b(); }
|
||||||
|
else { op_lsr_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//rol_dpx
|
||||||
|
case 0x36: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_rol_b(); }
|
||||||
|
else { op_rol_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ror_dpx
|
||||||
|
case 0x76: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
rd.l = op_readdp(dp + regs.x.w);
|
||||||
|
if(!regs.p.m) rd.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) { op_ror_b(); }
|
||||||
|
else { op_ror_w();
|
||||||
|
op_writedp(dp + regs.x.w + 1, rd.h); }
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, rd.l);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
#endif
|
||||||
181
bsnes/cpu/scpu/core/op_write.b
Executable file
181
bsnes/cpu/scpu/core/op_write.b
Executable file
@ -0,0 +1,181 @@
|
|||||||
|
sta_addr(0x8d, regs.p.m, regs.a.w),
|
||||||
|
stx_addr(0x8e, regs.p.x, regs.x.w),
|
||||||
|
sty_addr(0x8c, regs.p.x, regs.y.w),
|
||||||
|
stz_addr(0x9c, regs.p.m, 0x0000) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:if($1) last_cycle();
|
||||||
|
op_writedbr(aa.w, $2);
|
||||||
|
if($1) end;
|
||||||
|
4:last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, $2 >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_addrx(0x9d, regs.p.m, regs.a.w),
|
||||||
|
stz_addrx(0x9e, regs.p.m, 0x0000) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
4:if($1) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, $2);
|
||||||
|
if($1) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, $2 >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_addry(0x99) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:op_io();
|
||||||
|
4:if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_long(0x8f) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:aa.b = op_readpc();
|
||||||
|
4:if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writelong(aa.d + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_longx(0x9f) {
|
||||||
|
1:aa.l = op_readpc();
|
||||||
|
2:aa.h = op_readpc();
|
||||||
|
3:aa.b = op_readpc();
|
||||||
|
4:if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d + regs.x.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writelong(aa.d + regs.x.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_dp(0x85, regs.p.m, regs.a.w),
|
||||||
|
stx_dp(0x86, regs.p.x, regs.x.w),
|
||||||
|
sty_dp(0x84, regs.p.x, regs.y.w),
|
||||||
|
stz_dp(0x64, regs.p.m, 0x0000) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:if($1) last_cycle();
|
||||||
|
op_writedp(dp, $2);
|
||||||
|
if($1) end;
|
||||||
|
4:last_cycle();
|
||||||
|
op_writedp(dp + 1, $2 >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_dpx(0x95, regs.p.m, regs.a.w),
|
||||||
|
sty_dpx(0x94, regs.p.x, regs.y.w),
|
||||||
|
stz_dpx(0x74, regs.p.m, 0x0000) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:if($1) last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, $2);
|
||||||
|
if($1) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w + 1, $2 >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
stx_dpy(0x96) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:if(regs.p.x) last_cycle();
|
||||||
|
op_writedp(dp + regs.y.w, regs.x.l);
|
||||||
|
if(regs.p.x) end;
|
||||||
|
5:last_cycle();
|
||||||
|
op_writedp(dp + regs.y.w + 1, regs.x.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_idp(0x92) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
6:last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_ildp(0x87) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:aa.b = op_readdp(dp + 2);
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
7:last_cycle();
|
||||||
|
op_writelong(aa.d + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_idpx(0x81) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:op_io();
|
||||||
|
4:aa.l = op_readdp(dp + regs.x.w);
|
||||||
|
5:aa.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
7:last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_idpy(0x91) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:op_io();
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
7:last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_ildpy(0x97) {
|
||||||
|
1:dp = op_readpc();
|
||||||
|
2:op_io_cond2();
|
||||||
|
3:aa.l = op_readdp(dp);
|
||||||
|
4:aa.h = op_readdp(dp + 1);
|
||||||
|
5:aa.b = op_readdp(dp + 2);
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
7:last_cycle();
|
||||||
|
op_writelong(aa.d + regs.y.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_sr(0x83) {
|
||||||
|
1:sp = op_readpc();
|
||||||
|
2:op_io();
|
||||||
|
3:if(regs.p.m) last_cycle();
|
||||||
|
op_writesp(sp, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
4:last_cycle();
|
||||||
|
op_writesp(sp + 1, regs.a.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta_isry(0x93) {
|
||||||
|
1:sp = op_readpc();
|
||||||
|
2:op_io();
|
||||||
|
3:aa.l = op_readsp(sp);
|
||||||
|
4:aa.h = op_readsp(sp + 1);
|
||||||
|
5:op_io();
|
||||||
|
6:if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) end;
|
||||||
|
7:last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
}
|
||||||
293
bsnes/cpu/scpu/core/op_write.cpp
Executable file
293
bsnes/cpu/scpu/core/op_write.cpp
Executable file
@ -0,0 +1,293 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//sta_addr
|
||||||
|
case 0x8d: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.a.w);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.a.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stx_addr
|
||||||
|
case 0x8e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.x.w);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.x.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sty_addr
|
||||||
|
case 0x8c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.y.w);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.y.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stz_addr
|
||||||
|
case 0x9c: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, 0x0000);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, 0x0000 >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_addrx
|
||||||
|
case 0x9d: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, regs.a.w);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, regs.a.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stz_addrx
|
||||||
|
case 0x9e: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w, 0x0000);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.x.w + 1, 0x0000 >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_addry
|
||||||
|
case 0x99: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_long
|
||||||
|
case 0x8f: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
aa.b = op_readpc();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writelong(aa.d + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_longx
|
||||||
|
case 0x9f: {
|
||||||
|
aa.l = op_readpc();
|
||||||
|
aa.h = op_readpc();
|
||||||
|
aa.b = op_readpc();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d + regs.x.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writelong(aa.d + regs.x.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_dp
|
||||||
|
case 0x85: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedp(dp, regs.a.w);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + 1, regs.a.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stx_dp
|
||||||
|
case 0x86: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedp(dp, regs.x.w);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + 1, regs.x.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sty_dp
|
||||||
|
case 0x84: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedp(dp, regs.y.w);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + 1, regs.y.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stz_dp
|
||||||
|
case 0x64: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedp(dp, 0x0000);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + 1, 0x0000 >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_dpx
|
||||||
|
case 0x95: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, regs.a.w);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w + 1, regs.a.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sty_dpx
|
||||||
|
case 0x94: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, regs.y.w);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w + 1, regs.y.w >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stz_dpx
|
||||||
|
case 0x74: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w, 0x0000);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.x.w + 1, 0x0000 >> 8);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//stx_dpy
|
||||||
|
case 0x96: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.x) last_cycle();
|
||||||
|
op_writedp(dp + regs.y.w, regs.x.l);
|
||||||
|
if(regs.p.x) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedp(dp + regs.y.w + 1, regs.x.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_idp
|
||||||
|
case 0x92: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
aa.l = op_readdp(dp);
|
||||||
|
aa.h = op_readdp(dp + 1);
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_ildp
|
||||||
|
case 0x87: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
aa.l = op_readdp(dp);
|
||||||
|
aa.h = op_readdp(dp + 1);
|
||||||
|
aa.b = op_readdp(dp + 2);
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writelong(aa.d + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_idpx
|
||||||
|
case 0x81: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
op_io();
|
||||||
|
aa.l = op_readdp(dp + regs.x.w);
|
||||||
|
aa.h = op_readdp(dp + regs.x.w + 1);
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_idpy
|
||||||
|
case 0x91: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
aa.l = op_readdp(dp);
|
||||||
|
aa.h = op_readdp(dp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_ildpy
|
||||||
|
case 0x97: {
|
||||||
|
dp = op_readpc();
|
||||||
|
op_io_cond2();
|
||||||
|
aa.l = op_readdp(dp);
|
||||||
|
aa.h = op_readdp(dp + 1);
|
||||||
|
aa.b = op_readdp(dp + 2);
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writelong(aa.d + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writelong(aa.d + regs.y.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_sr
|
||||||
|
case 0x83: {
|
||||||
|
sp = op_readpc();
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writesp(sp, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writesp(sp + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//sta_isry
|
||||||
|
case 0x93: {
|
||||||
|
sp = op_readpc();
|
||||||
|
op_io();
|
||||||
|
aa.l = op_readsp(sp);
|
||||||
|
aa.h = op_readsp(sp + 1);
|
||||||
|
op_io();
|
||||||
|
if(regs.p.m) last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w, regs.a.l);
|
||||||
|
if(regs.p.m) break;
|
||||||
|
last_cycle();
|
||||||
|
op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
#endif
|
||||||
371
bsnes/cpu/scpu/core/opfn.cpp
Executable file
371
bsnes/cpu/scpu/core/opfn.cpp
Executable file
@ -0,0 +1,371 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//op_read
|
||||||
|
inline void sCPU::op_adc_b() {
|
||||||
|
int r;
|
||||||
|
if(regs.p.d) {
|
||||||
|
uint8 n0 = (regs.a.l ) & 15;
|
||||||
|
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||||
|
n0 += (rd.l & 15) + regs.p.c;
|
||||||
|
if(n0 > 9) {
|
||||||
|
n0 = (n0 - 10) & 15;
|
||||||
|
n1++;
|
||||||
|
}
|
||||||
|
n1 += ((rd.l >> 4) & 15);
|
||||||
|
if(n1 > 9) {
|
||||||
|
n1 = (n1 - 10) & 15;
|
||||||
|
regs.p.c = 1;
|
||||||
|
} else {
|
||||||
|
regs.p.c = 0;
|
||||||
|
}
|
||||||
|
r = (n1 << 4) | n0;
|
||||||
|
} else {
|
||||||
|
r = regs.a.l + rd.l + regs.p.c;
|
||||||
|
regs.p.c = r > 0xff;
|
||||||
|
}
|
||||||
|
regs.p.n = r & 0x80;
|
||||||
|
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
|
||||||
|
regs.p.z = (uint8)r == 0;
|
||||||
|
regs.a.l = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_adc_w() {
|
||||||
|
int r;
|
||||||
|
if(regs.p.d) {
|
||||||
|
uint8 n0 = (regs.a.w ) & 15;
|
||||||
|
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||||
|
uint8 n2 = (regs.a.w >> 8) & 15;
|
||||||
|
uint8 n3 = (regs.a.w >> 12) & 15;
|
||||||
|
n0 += (rd.w & 15) + regs.p.c;
|
||||||
|
if(n0 > 9) {
|
||||||
|
n0 = (n0 - 10) & 15;
|
||||||
|
n1++;
|
||||||
|
}
|
||||||
|
n1 += ((rd.w >> 4) & 15);
|
||||||
|
if(n1 > 9) {
|
||||||
|
n1 = (n1 - 10) & 15;
|
||||||
|
n2++;
|
||||||
|
}
|
||||||
|
n2 += ((rd.w >> 8) & 15);
|
||||||
|
if(n2 > 9) {
|
||||||
|
n2 = (n2 - 10) & 15;
|
||||||
|
n3++;
|
||||||
|
}
|
||||||
|
n3 += ((rd.w >> 12) & 15);
|
||||||
|
if(n3 > 9) {
|
||||||
|
n3 = (n3 - 10) & 15;
|
||||||
|
regs.p.c = 1;
|
||||||
|
} else {
|
||||||
|
regs.p.c = 0;
|
||||||
|
}
|
||||||
|
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | n0;
|
||||||
|
} else {
|
||||||
|
r = regs.a.w + rd.w + regs.p.c;
|
||||||
|
regs.p.c = r > 0xffff;
|
||||||
|
}
|
||||||
|
regs.p.n = r & 0x8000;
|
||||||
|
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
|
||||||
|
regs.p.z = (uint16)r == 0;
|
||||||
|
regs.a.w = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_and_b() {
|
||||||
|
regs.a.l &= rd.l;
|
||||||
|
regs.p.n = regs.a.l & 0x80;
|
||||||
|
regs.p.z = regs.a.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_and_w() {
|
||||||
|
regs.a.w &= rd.w;
|
||||||
|
regs.p.n = regs.a.w & 0x8000;
|
||||||
|
regs.p.z = regs.a.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_bit_b() {
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.v = rd.l & 0x40;
|
||||||
|
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_bit_w() {
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.v = rd.w & 0x4000;
|
||||||
|
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cmp_b() {
|
||||||
|
int r = regs.a.l - rd.l;
|
||||||
|
regs.p.n = r & 0x80;
|
||||||
|
regs.p.z = (uint8)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cmp_w() {
|
||||||
|
int r = regs.a.w - rd.w;
|
||||||
|
regs.p.n = r & 0x8000;
|
||||||
|
regs.p.z = (uint16)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cpx_b() {
|
||||||
|
int r = regs.x.l - rd.l;
|
||||||
|
regs.p.n = r & 0x80;
|
||||||
|
regs.p.z = (uint8)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cpx_w() {
|
||||||
|
int r = regs.x.w - rd.w;
|
||||||
|
regs.p.n = r & 0x8000;
|
||||||
|
regs.p.z = (uint16)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cpy_b() {
|
||||||
|
int r = regs.y.l - rd.l;
|
||||||
|
regs.p.n = r & 0x80;
|
||||||
|
regs.p.z = (uint8)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_cpy_w() {
|
||||||
|
int r = regs.y.w - rd.w;
|
||||||
|
regs.p.n = r & 0x8000;
|
||||||
|
regs.p.z = (uint16)r == 0;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_eor_b() {
|
||||||
|
regs.a.l ^= rd.l;
|
||||||
|
regs.p.n = regs.a.l & 0x80;
|
||||||
|
regs.p.z = regs.a.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_eor_w() {
|
||||||
|
regs.a.w ^= rd.w;
|
||||||
|
regs.p.n = regs.a.w & 0x8000;
|
||||||
|
regs.p.z = regs.a.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_lda_b() {
|
||||||
|
regs.a.l = rd.l;
|
||||||
|
regs.p.n = regs.a.l & 0x80;
|
||||||
|
regs.p.z = regs.a.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_lda_w() {
|
||||||
|
regs.a.w = rd.w;
|
||||||
|
regs.p.n = regs.a.w & 0x8000;
|
||||||
|
regs.p.z = regs.a.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ldx_b() {
|
||||||
|
regs.x.l = rd.l;
|
||||||
|
regs.p.n = regs.x.l & 0x80;
|
||||||
|
regs.p.z = regs.x.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ldx_w() {
|
||||||
|
regs.x.w = rd.w;
|
||||||
|
regs.p.n = regs.x.w & 0x8000;
|
||||||
|
regs.p.z = regs.x.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ldy_b() {
|
||||||
|
regs.y.l = rd.l;
|
||||||
|
regs.p.n = regs.y.l & 0x80;
|
||||||
|
regs.p.z = regs.y.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ldy_w() {
|
||||||
|
regs.y.w = rd.w;
|
||||||
|
regs.p.n = regs.y.w & 0x8000;
|
||||||
|
regs.p.z = regs.y.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ora_b() {
|
||||||
|
regs.a.l |= rd.l;
|
||||||
|
regs.p.n = regs.a.l & 0x80;
|
||||||
|
regs.p.z = regs.a.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ora_w() {
|
||||||
|
regs.a.w |= rd.w;
|
||||||
|
regs.p.n = regs.a.w & 0x8000;
|
||||||
|
regs.p.z = regs.a.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_sbc_b() {
|
||||||
|
int r;
|
||||||
|
if(regs.p.d) {
|
||||||
|
uint8 n0 = (regs.a.l ) & 15;
|
||||||
|
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||||
|
n0 -= ((rd.l ) & 15) + !regs.p.c;
|
||||||
|
n1 -= ((rd.l >> 4) & 15);
|
||||||
|
if(n0 > 9) {
|
||||||
|
n0 += 10;
|
||||||
|
n1--;
|
||||||
|
}
|
||||||
|
if(n1 > 9) {
|
||||||
|
n1 += 10;
|
||||||
|
regs.p.c = 0;
|
||||||
|
} else {
|
||||||
|
regs.p.c = 1;
|
||||||
|
}
|
||||||
|
r = (n1 << 4) | (n0);
|
||||||
|
} else {
|
||||||
|
r = regs.a.l - rd.l - !regs.p.c;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
regs.p.n = r & 0x80;
|
||||||
|
regs.p.v = (regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
|
||||||
|
regs.p.z = (uint8)r == 0;
|
||||||
|
regs.a.l = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_sbc_w() {
|
||||||
|
int r;
|
||||||
|
if(regs.p.d) {
|
||||||
|
uint8 n0 = (regs.a.w ) & 15;
|
||||||
|
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||||
|
uint8 n2 = (regs.a.w >> 8) & 15;
|
||||||
|
uint8 n3 = (regs.a.w >> 12) & 15;
|
||||||
|
n0 -= ((rd.w ) & 15) + !regs.p.c;
|
||||||
|
n1 -= ((rd.w >> 4) & 15);
|
||||||
|
n2 -= ((rd.w >> 8) & 15);
|
||||||
|
n3 -= ((rd.w >> 12) & 15);
|
||||||
|
if(n0 > 9) {
|
||||||
|
n0 += 10;
|
||||||
|
n1--;
|
||||||
|
}
|
||||||
|
if(n1 > 9) {
|
||||||
|
n1 += 10;
|
||||||
|
n2--;
|
||||||
|
}
|
||||||
|
if(n2 > 9) {
|
||||||
|
n2 += 10;
|
||||||
|
n3--;
|
||||||
|
}
|
||||||
|
if(n3 > 9) {
|
||||||
|
n3 += 10;
|
||||||
|
regs.p.c = 0;
|
||||||
|
} else {
|
||||||
|
regs.p.c = 1;
|
||||||
|
}
|
||||||
|
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
|
||||||
|
} else {
|
||||||
|
r = regs.a.w - rd.w - !regs.p.c;
|
||||||
|
regs.p.c = r >= 0;
|
||||||
|
}
|
||||||
|
regs.p.n = r & 0x8000;
|
||||||
|
regs.p.v = (regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
|
||||||
|
regs.p.z = (uint16)r == 0;
|
||||||
|
regs.a.w = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//op_rmw
|
||||||
|
inline void sCPU::op_inc_b() {
|
||||||
|
rd.l++;
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_inc_w() {
|
||||||
|
rd.w++;
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_dec_b() {
|
||||||
|
rd.l--;
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_dec_w() {
|
||||||
|
rd.w--;
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_asl_b() {
|
||||||
|
regs.p.c = rd.l & 0x80;
|
||||||
|
rd.l <<= 1;
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_asl_w() {
|
||||||
|
regs.p.c = rd.w & 0x8000;
|
||||||
|
rd.w <<= 1;
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_lsr_b() {
|
||||||
|
regs.p.c = rd.l & 1;
|
||||||
|
rd.l >>= 1;
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_lsr_w() {
|
||||||
|
regs.p.c = rd.w & 1;
|
||||||
|
rd.w >>= 1;
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_rol_b() {
|
||||||
|
unsigned carry = (unsigned)regs.p.c;
|
||||||
|
regs.p.c = rd.l & 0x80;
|
||||||
|
rd.l = (rd.l << 1) | carry;
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_rol_w() {
|
||||||
|
unsigned carry = (unsigned)regs.p.c;
|
||||||
|
regs.p.c = rd.w & 0x8000;
|
||||||
|
rd.w = (rd.w << 1) | carry;
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ror_b() {
|
||||||
|
unsigned carry = (unsigned)regs.p.c << 7;
|
||||||
|
regs.p.c = rd.l & 1;
|
||||||
|
rd.l = carry | (rd.l >> 1);
|
||||||
|
regs.p.n = rd.l & 0x80;
|
||||||
|
regs.p.z = rd.l == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_ror_w() {
|
||||||
|
unsigned carry = (unsigned)regs.p.c << 15;
|
||||||
|
regs.p.c = rd.w & 1;
|
||||||
|
rd.w = carry | (rd.w >> 1);
|
||||||
|
regs.p.n = rd.w & 0x8000;
|
||||||
|
regs.p.z = rd.w == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_trb_b() {
|
||||||
|
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||||
|
rd.l &= ~regs.a.l;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_trb_w() {
|
||||||
|
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||||
|
rd.w &= ~regs.a.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_tsb_b() {
|
||||||
|
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||||
|
rd.l |= regs.a.l;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sCPU::op_tsb_w() {
|
||||||
|
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||||
|
rd.w |= regs.a.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ifdef SCPU_CPP
|
||||||
12
bsnes/cpu/scpu/core/scpugen.cpp
Executable file
12
bsnes/cpu/scpu/core/scpugen.cpp
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#define CLASS_NAME "sCPU"
|
||||||
|
#include <tool/opgen_switch.cpp>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
generate("op_read.cpp", "op_read.b");
|
||||||
|
generate("op_write.cpp", "op_write.b");
|
||||||
|
generate("op_rmw.cpp", "op_rmw.b");
|
||||||
|
generate("op_pc.cpp", "op_pc.b");
|
||||||
|
generate("op_misc.cpp", "op_misc.b");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
271
bsnes/cpu/scpu/dma/dma.cpp
Executable file
271
bsnes/cpu/scpu/dma/dma.cpp
Executable file
@ -0,0 +1,271 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
void sCPU::dma_add_clocks(unsigned clocks) {
|
||||||
|
status.dma_clocks += clocks;
|
||||||
|
add_clocks(clocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sCPU::dma_addr_valid(uint32 abus) {
|
||||||
|
//reads from B-bus or S-CPU registers are invalid
|
||||||
|
if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff]
|
||||||
|
if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff]
|
||||||
|
if((abus & 0x40ffe0) == 0x4200) return false; //$[00-3f|80-bf]:[4200-421f]
|
||||||
|
if((abus & 0x40ff80) == 0x4300) return false; //$[00-3f|80-bf]:[4300-437f]
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 sCPU::dma_read(uint32 abus) {
|
||||||
|
if(dma_addr_valid(abus) == false) return 0x00; //does not return S-CPU MDR
|
||||||
|
return bus.read(abus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
|
||||||
|
if(direction == 0) {
|
||||||
|
//a->b transfer (to $21xx)
|
||||||
|
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) {
|
||||||
|
//illegal WRAM->WRAM transfer (bus conflict)
|
||||||
|
//read most likely occurs; no write occurs
|
||||||
|
//read is irrelevent, as it cannot be observed by software
|
||||||
|
dma_add_clocks(8);
|
||||||
|
} else {
|
||||||
|
dma_add_clocks(4);
|
||||||
|
uint8 data = dma_read(abus);
|
||||||
|
dma_add_clocks(4);
|
||||||
|
bus.write(0x2100 | bbus, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//b->a transfer (from $21xx)
|
||||||
|
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) {
|
||||||
|
//illegal WRAM->WRAM transfer (bus conflict)
|
||||||
|
//no read occurs; write does occur
|
||||||
|
dma_add_clocks(8);
|
||||||
|
bus.write(abus, 0x00); //does not write S-CPU MDR
|
||||||
|
} else {
|
||||||
|
dma_add_clocks(4);
|
||||||
|
uint8 data = bus.read(0x2100 | bbus);
|
||||||
|
dma_add_clocks(4);
|
||||||
|
if(dma_addr_valid(abus) == true) {
|
||||||
|
bus.write(abus, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle_edge();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* address calculation functions
|
||||||
|
*****/
|
||||||
|
|
||||||
|
uint8 sCPU::dma_bbus(uint8 i, uint8 index) {
|
||||||
|
switch(channel[i].xfermode) { default:
|
||||||
|
case 0: return (channel[i].destaddr); //0
|
||||||
|
case 1: return (channel[i].destaddr + (index & 1)); //0,1
|
||||||
|
case 2: return (channel[i].destaddr); //0,0
|
||||||
|
case 3: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1
|
||||||
|
case 4: return (channel[i].destaddr + (index & 3)); //0,1,2,3
|
||||||
|
case 5: return (channel[i].destaddr + (index & 1)); //0,1,0,1
|
||||||
|
case 6: return (channel[i].destaddr); //0,0 [2]
|
||||||
|
case 7: return (channel[i].destaddr + ((index >> 1) & 1)); //0,0,1,1 [3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 sCPU::dma_addr(uint8 i) {
|
||||||
|
uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||||
|
|
||||||
|
if(channel[i].fixedxfer == false) {
|
||||||
|
if(channel[i].reversexfer == false) {
|
||||||
|
channel[i].srcaddr++;
|
||||||
|
} else {
|
||||||
|
channel[i].srcaddr--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 sCPU::hdma_addr(uint8 i) {
|
||||||
|
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 sCPU::hdma_iaddr(uint8 i) {
|
||||||
|
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* DMA functions
|
||||||
|
*****/
|
||||||
|
|
||||||
|
uint8 sCPU::dma_enabled_channels() {
|
||||||
|
uint8 r = 0;
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(channel[i].dma_enabled) r++;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::dma_run() {
|
||||||
|
dma_add_clocks(8);
|
||||||
|
cycle_edge();
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(channel[i].dma_enabled == false) continue;
|
||||||
|
dma_add_clocks(8);
|
||||||
|
cycle_edge();
|
||||||
|
|
||||||
|
unsigned index = 0;
|
||||||
|
do {
|
||||||
|
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
|
||||||
|
} while(channel[i].dma_enabled && --channel[i].xfersize);
|
||||||
|
|
||||||
|
channel[i].dma_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.irq_lock = true;
|
||||||
|
event.enqueue(2, EventIrqLockRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* HDMA functions
|
||||||
|
*****/
|
||||||
|
|
||||||
|
inline bool sCPU::hdma_active(uint8 i) {
|
||||||
|
return (channel[i].hdma_enabled && !channel[i].hdma_completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool sCPU::hdma_active_after(uint8 i) {
|
||||||
|
for(unsigned n = i + 1; n < 8; n++) {
|
||||||
|
if(hdma_active(n) == true) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 sCPU::hdma_enabled_channels() {
|
||||||
|
uint8 r = 0;
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(channel[i].hdma_enabled) r++;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 sCPU::hdma_active_channels() {
|
||||||
|
uint8 r = 0;
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(hdma_active(i) == true) r++;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::hdma_update(uint8 i) {
|
||||||
|
channel[i].hdma_line_counter = dma_read(hdma_addr(i));
|
||||||
|
dma_add_clocks(8);
|
||||||
|
|
||||||
|
channel[i].hdma_completed = (channel[i].hdma_line_counter == 0);
|
||||||
|
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
|
||||||
|
|
||||||
|
if(channel[i].hdma_indirect) {
|
||||||
|
channel[i].hdma_iaddr = dma_read(hdma_addr(i)) << 8;
|
||||||
|
dma_add_clocks(8);
|
||||||
|
|
||||||
|
if(!channel[i].hdma_completed || hdma_active_after(i)) {
|
||||||
|
channel[i].hdma_iaddr >>= 8;
|
||||||
|
channel[i].hdma_iaddr |= dma_read(hdma_addr(i)) << 8;
|
||||||
|
dma_add_clocks(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::hdma_run() {
|
||||||
|
dma_add_clocks(8);
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(hdma_active(i) == false) continue;
|
||||||
|
channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
|
||||||
|
|
||||||
|
if(channel[i].hdma_do_transfer) {
|
||||||
|
static const unsigned transfer_length[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
|
||||||
|
unsigned length = transfer_length[channel[i].xfermode];
|
||||||
|
for(unsigned index = 0; index < length; index++) {
|
||||||
|
unsigned addr = !channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i);
|
||||||
|
dma_transfer(channel[i].direction, dma_bbus(i, index), addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(hdma_active(i) == false) continue;
|
||||||
|
|
||||||
|
channel[i].hdma_line_counter--;
|
||||||
|
channel[i].hdma_do_transfer = bool(channel[i].hdma_line_counter & 0x80);
|
||||||
|
if((channel[i].hdma_line_counter & 0x7f) == 0) {
|
||||||
|
hdma_update(i);
|
||||||
|
} else {
|
||||||
|
dma_add_clocks(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.irq_lock = true;
|
||||||
|
event.enqueue(2, EventIrqLockRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::hdma_init_reset() {
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
channel[i].hdma_completed = false;
|
||||||
|
channel[i].hdma_do_transfer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::hdma_init() {
|
||||||
|
dma_add_clocks(8);
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
if(!channel[i].hdma_enabled) continue;
|
||||||
|
channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer
|
||||||
|
|
||||||
|
channel[i].hdma_addr = channel[i].srcaddr;
|
||||||
|
hdma_update(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
status.irq_lock = true;
|
||||||
|
event.enqueue(2, EventIrqLockRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* power / reset functions
|
||||||
|
*****/
|
||||||
|
|
||||||
|
void sCPU::dma_power() {
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
channel[i].dmap = 0xff;
|
||||||
|
channel[i].direction = 1;
|
||||||
|
channel[i].hdma_indirect = true;
|
||||||
|
channel[i].reversexfer = true;
|
||||||
|
channel[i].fixedxfer = true;
|
||||||
|
channel[i].xfermode = 7;
|
||||||
|
|
||||||
|
channel[i].destaddr = 0xff;
|
||||||
|
|
||||||
|
channel[i].srcaddr = 0xffff;
|
||||||
|
channel[i].srcbank = 0xff;
|
||||||
|
|
||||||
|
channel[i].xfersize = 0xffff;
|
||||||
|
//channel[i].hdma_iaddr = 0xffff; //union with xfersize
|
||||||
|
channel[i].hdma_ibank = 0xff;
|
||||||
|
|
||||||
|
channel[i].hdma_addr = 0xffff;
|
||||||
|
channel[i].hdma_line_counter = 0xff;
|
||||||
|
channel[i].unknown = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::dma_reset() {
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
channel[i].dma_enabled = false;
|
||||||
|
channel[i].hdma_enabled = false;
|
||||||
|
|
||||||
|
channel[i].hdma_completed = false;
|
||||||
|
channel[i].hdma_do_transfer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ifdef SCPU_CPP
|
||||||
71
bsnes/cpu/scpu/dma/dma.hpp
Executable file
71
bsnes/cpu/scpu/dma/dma.hpp
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
struct {
|
||||||
|
//$420b
|
||||||
|
bool dma_enabled;
|
||||||
|
|
||||||
|
//$420c
|
||||||
|
bool hdma_enabled;
|
||||||
|
|
||||||
|
//$43x0
|
||||||
|
uint8 dmap;
|
||||||
|
bool direction;
|
||||||
|
bool hdma_indirect;
|
||||||
|
bool reversexfer;
|
||||||
|
bool fixedxfer;
|
||||||
|
uint8 xfermode;
|
||||||
|
|
||||||
|
//$43x1
|
||||||
|
uint8 destaddr;
|
||||||
|
|
||||||
|
//$43x2-$43x3
|
||||||
|
uint16 srcaddr;
|
||||||
|
|
||||||
|
//$43x4
|
||||||
|
uint8 srcbank;
|
||||||
|
|
||||||
|
//$43x5-$43x6
|
||||||
|
union {
|
||||||
|
uint16 xfersize;
|
||||||
|
uint16 hdma_iaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//$43x7
|
||||||
|
uint8 hdma_ibank;
|
||||||
|
|
||||||
|
//$43x8-$43x9
|
||||||
|
uint16 hdma_addr;
|
||||||
|
|
||||||
|
//$43xa
|
||||||
|
uint8 hdma_line_counter;
|
||||||
|
|
||||||
|
//$43xb/$43xf
|
||||||
|
uint8 unknown;
|
||||||
|
|
||||||
|
//internal variables
|
||||||
|
bool hdma_completed;
|
||||||
|
bool hdma_do_transfer;
|
||||||
|
} channel[8];
|
||||||
|
|
||||||
|
void dma_add_clocks(unsigned clocks);
|
||||||
|
bool dma_addr_valid(uint32 abus);
|
||||||
|
uint8 dma_read(uint32 abus);
|
||||||
|
void dma_transfer(bool direction, uint8 bbus, uint32 abus);
|
||||||
|
|
||||||
|
uint8 dma_bbus(uint8 i, uint8 index);
|
||||||
|
uint32 dma_addr(uint8 i);
|
||||||
|
uint32 hdma_addr(uint8 i);
|
||||||
|
uint32 hdma_iaddr(uint8 i);
|
||||||
|
|
||||||
|
uint8 dma_enabled_channels();
|
||||||
|
void dma_run();
|
||||||
|
|
||||||
|
bool hdma_active(uint8 i);
|
||||||
|
bool hdma_active_after(uint8 i);
|
||||||
|
uint8 hdma_enabled_channels();
|
||||||
|
uint8 hdma_active_channels();
|
||||||
|
void hdma_update(uint8 i);
|
||||||
|
void hdma_run();
|
||||||
|
void hdma_init_reset();
|
||||||
|
void hdma_init();
|
||||||
|
|
||||||
|
void dma_power();
|
||||||
|
void dma_reset();
|
||||||
125
bsnes/cpu/scpu/memory/memory.cpp
Executable file
125
bsnes/cpu/scpu/memory/memory.cpp
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* These 3 functions control bus timing for the CPU.
|
||||||
|
* cpu_io is an I/O cycle, and always 6 clock cycles long.
|
||||||
|
* mem_read / mem_write indicate memory access bus cycles.
|
||||||
|
* they are either 6, 8, or 12 bus cycles long, depending
|
||||||
|
* both on location and the $420d.d0 FastROM enable bit.
|
||||||
|
*****/
|
||||||
|
|
||||||
|
void sCPU::op_io() {
|
||||||
|
status.clock_count = 6;
|
||||||
|
precycle_edge();
|
||||||
|
add_clocks(6);
|
||||||
|
cycle_edge();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 sCPU::op_read(uint32 addr) {
|
||||||
|
status.clock_count = bus.speed(addr);
|
||||||
|
precycle_edge();
|
||||||
|
add_clocks(status.clock_count - 4);
|
||||||
|
regs.mdr = bus.read(addr);
|
||||||
|
add_clocks(4);
|
||||||
|
cycle_edge();
|
||||||
|
return regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::op_write(uint32 addr, uint8 data) {
|
||||||
|
status.clock_count = bus.speed(addr);
|
||||||
|
precycle_edge();
|
||||||
|
add_clocks(status.clock_count);
|
||||||
|
regs.mdr = data;
|
||||||
|
bus.write(addr, regs.mdr);
|
||||||
|
cycle_edge();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readpc() {
|
||||||
|
return op_read((regs.pc.b << 16) + regs.pc.w++);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readstack() {
|
||||||
|
if(regs.e) {
|
||||||
|
regs.s.l++;
|
||||||
|
} else {
|
||||||
|
regs.s.w++;
|
||||||
|
}
|
||||||
|
return op_read(regs.s.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readstackn() {
|
||||||
|
return op_read(++regs.s.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readaddr(uint32 addr) {
|
||||||
|
return op_read(addr & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readlong(uint32 addr) {
|
||||||
|
return op_read(addr & 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readdbr(uint32 addr) {
|
||||||
|
return op_read(((regs.db << 16) + addr) & 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readpbr(uint32 addr) {
|
||||||
|
return op_read((regs.pc.b << 16) + (addr & 0xffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readdp(uint32 addr) {
|
||||||
|
if(regs.e && regs.d.l == 0x00) {
|
||||||
|
return op_read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
|
||||||
|
} else {
|
||||||
|
return op_read((regs.d + (addr & 0xffff)) & 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline uint8 sCPU::op_readsp(uint32 addr) {
|
||||||
|
return op_read((regs.s + (addr & 0xffff)) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writestack(uint8 data) {
|
||||||
|
op_write(regs.s.w, data);
|
||||||
|
if(regs.e) {
|
||||||
|
regs.s.l--;
|
||||||
|
} else {
|
||||||
|
regs.s.w--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writestackn(uint8 data) {
|
||||||
|
op_write(regs.s.w--, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writeaddr(uint32 addr, uint8 data) {
|
||||||
|
op_write(addr & 0xffff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writelong(uint32 addr, uint8 data) {
|
||||||
|
op_write(addr & 0xffffff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writedbr(uint32 addr, uint8 data) {
|
||||||
|
op_write(((regs.db << 16) + addr) & 0xffffff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writepbr(uint32 addr, uint8 data) {
|
||||||
|
op_write((regs.pc.b << 16) + (addr & 0xffff), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writedp(uint32 addr, uint8 data) {
|
||||||
|
if(regs.e && regs.d.l == 0x00) {
|
||||||
|
op_write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
|
||||||
|
} else {
|
||||||
|
op_write((regs.d + (addr & 0xffff)) & 0xffff, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysinline void sCPU::op_writesp(uint32 addr, uint8 data) {
|
||||||
|
op_write((regs.s + (addr & 0xffff)) & 0xffff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ifdef SCPU_CPP
|
||||||
35
bsnes/cpu/scpu/memory/memory.hpp
Executable file
35
bsnes/cpu/scpu/memory/memory.hpp
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
/*****
|
||||||
|
* CPU<>APU communication ports
|
||||||
|
*****/
|
||||||
|
uint8 apu_port[4];
|
||||||
|
uint8 port_read(uint8 port) { return apu_port[port & 3]; }
|
||||||
|
void port_write(uint8 port, uint8 data) { apu_port[port & 3] = data; }
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* core CPU bus functions
|
||||||
|
*****/
|
||||||
|
void op_io();
|
||||||
|
uint8 op_read(uint32 addr);
|
||||||
|
void op_write(uint32 addr, uint8 data);
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* helper memory addressing functions used by CPU core
|
||||||
|
*****/
|
||||||
|
uint8 op_readpc ();
|
||||||
|
uint8 op_readstack ();
|
||||||
|
uint8 op_readstackn();
|
||||||
|
uint8 op_readaddr (uint32 addr);
|
||||||
|
uint8 op_readlong (uint32 addr);
|
||||||
|
uint8 op_readdbr (uint32 addr);
|
||||||
|
uint8 op_readpbr (uint32 addr);
|
||||||
|
uint8 op_readdp (uint32 addr);
|
||||||
|
uint8 op_readsp (uint32 addr);
|
||||||
|
|
||||||
|
void op_writestack (uint8 data);
|
||||||
|
void op_writestackn(uint8 data);
|
||||||
|
void op_writeaddr (uint32 addr, uint8 data);
|
||||||
|
void op_writelong (uint32 addr, uint8 data);
|
||||||
|
void op_writedbr (uint32 addr, uint8 data);
|
||||||
|
void op_writepbr (uint32 addr, uint8 data);
|
||||||
|
void op_writedp (uint32 addr, uint8 data);
|
||||||
|
void op_writesp (uint32 addr, uint8 data);
|
||||||
534
bsnes/cpu/scpu/mmio/mmio.cpp
Executable file
534
bsnes/cpu/scpu/mmio/mmio.cpp
Executable file
@ -0,0 +1,534 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
uint8 sCPU::pio() { return status.pio; }
|
||||||
|
bool sCPU::joylatch() { return status.joypad_strobe_latch; }
|
||||||
|
|
||||||
|
//WMDATA
|
||||||
|
uint8 sCPU::mmio_r2180() {
|
||||||
|
uint8 r = bus.read(0x7e0000 | status.wram_addr);
|
||||||
|
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WMDATA
|
||||||
|
void sCPU::mmio_w2180(uint8 data) {
|
||||||
|
bus.write(0x7e0000 | status.wram_addr, data);
|
||||||
|
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WMADDL
|
||||||
|
void sCPU::mmio_w2181(uint8 data) {
|
||||||
|
status.wram_addr = (status.wram_addr & 0xffff00) | (data);
|
||||||
|
status.wram_addr &= 0x01ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WMADDM
|
||||||
|
void sCPU::mmio_w2182(uint8 data) {
|
||||||
|
status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8);
|
||||||
|
status.wram_addr &= 0x01ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WMADDH
|
||||||
|
void sCPU::mmio_w2183(uint8 data) {
|
||||||
|
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
|
||||||
|
status.wram_addr &= 0x01ffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//JOYSER0
|
||||||
|
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
|
||||||
|
//strobing $4016.d0 affects both controller port latches.
|
||||||
|
//$4017 bit 0 writes are ignored.
|
||||||
|
void sCPU::mmio_w4016(uint8 data) {
|
||||||
|
status.joypad_strobe_latch = !!(data & 1);
|
||||||
|
|
||||||
|
if(status.joypad_strobe_latch == 1) {
|
||||||
|
snes.input.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//JOYSER0
|
||||||
|
//7-2 = MDR
|
||||||
|
//1-0 = Joypad serial data
|
||||||
|
//
|
||||||
|
//TODO: test whether strobe latch of zero returns
|
||||||
|
//realtime or buffered status of joypadN.b
|
||||||
|
uint8 sCPU::mmio_r4016() {
|
||||||
|
uint8 r = regs.mdr & 0xfc;
|
||||||
|
r |= snes.input.port_read(0) & 3;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//JOYSER1
|
||||||
|
//7-5 = MDR
|
||||||
|
//4-2 = Always 1 (pins are connected to GND)
|
||||||
|
//1-0 = Joypad serial data
|
||||||
|
uint8 sCPU::mmio_r4017() {
|
||||||
|
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||||
|
r |= snes.input.port_read(1) & 3;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NMITIMEN
|
||||||
|
void sCPU::mmio_w4200(uint8 data) {
|
||||||
|
status.auto_joypad_poll = !!(data & 0x01);
|
||||||
|
nmitimen_update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRIO
|
||||||
|
void sCPU::mmio_w4201(uint8 data) {
|
||||||
|
if((status.pio & 0x80) && !(data & 0x80)) {
|
||||||
|
ppu.latch_counters();
|
||||||
|
}
|
||||||
|
status.pio = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRMPYA
|
||||||
|
void sCPU::mmio_w4202(uint8 data) {
|
||||||
|
status.mul_a = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRMPYB
|
||||||
|
void sCPU::mmio_w4203(uint8 data) {
|
||||||
|
status.mul_b = data;
|
||||||
|
status.r4216 = status.mul_a * status.mul_b;
|
||||||
|
|
||||||
|
status.alu_lock = true;
|
||||||
|
event.enqueue(snes.config.cpu.alu_mul_delay, EventAluLockRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRDIVL
|
||||||
|
void sCPU::mmio_w4204(uint8 data) {
|
||||||
|
status.div_a = (status.div_a & 0xff00) | (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRDIVH
|
||||||
|
void sCPU::mmio_w4205(uint8 data) {
|
||||||
|
status.div_a = (status.div_a & 0x00ff) | (data << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//WRDIVB
|
||||||
|
void sCPU::mmio_w4206(uint8 data) {
|
||||||
|
status.div_b = data;
|
||||||
|
status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//HTIMEL
|
||||||
|
void sCPU::mmio_w4207(uint8 data) {
|
||||||
|
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
|
||||||
|
status.hirq_pos &= 0x01ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//HTIMEH
|
||||||
|
void sCPU::mmio_w4208(uint8 data) {
|
||||||
|
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
|
||||||
|
status.hirq_pos &= 0x01ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//VTIMEL
|
||||||
|
void sCPU::mmio_w4209(uint8 data) {
|
||||||
|
status.virq_pos = (status.virq_pos & ~0xff) | (data);
|
||||||
|
status.virq_pos &= 0x01ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//VTIMEH
|
||||||
|
void sCPU::mmio_w420a(uint8 data) {
|
||||||
|
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
|
||||||
|
status.virq_pos &= 0x01ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DMAEN
|
||||||
|
void sCPU::mmio_w420b(uint8 data) {
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
channel[i].dma_enabled = data & (1 << i);
|
||||||
|
}
|
||||||
|
if(data) status.dma_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//HDMAEN
|
||||||
|
void sCPU::mmio_w420c(uint8 data) {
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
channel[i].hdma_enabled = data & (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MEMSEL
|
||||||
|
void sCPU::mmio_w420d(uint8 data) {
|
||||||
|
bus.set_speed(data & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDNMI
|
||||||
|
//7 = NMI acknowledge
|
||||||
|
//6-4 = MDR
|
||||||
|
//3-0 = CPU (5a22) version
|
||||||
|
uint8 sCPU::mmio_r4210() {
|
||||||
|
uint8 r = (regs.mdr & 0x70);
|
||||||
|
r |= (uint8)(rdnmi()) << 7;
|
||||||
|
r |= (cpu_version & 0x0f);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TIMEUP
|
||||||
|
//7 = IRQ acknowledge
|
||||||
|
//6-0 = MDR
|
||||||
|
uint8 sCPU::mmio_r4211() {
|
||||||
|
uint8 r = (regs.mdr & 0x7f);
|
||||||
|
r |= (uint8)(timeup()) << 7;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//HVBJOY
|
||||||
|
//7 = VBLANK acknowledge
|
||||||
|
//6 = HBLANK acknowledge
|
||||||
|
//5-1 = MDR
|
||||||
|
//0 = JOYPAD acknowledge
|
||||||
|
uint8 sCPU::mmio_r4212() {
|
||||||
|
uint8 r = (regs.mdr & 0x3e);
|
||||||
|
uint16 vs = ppu.overscan() == false ? 225 : 240;
|
||||||
|
|
||||||
|
//auto joypad polling
|
||||||
|
if(ppu.vcounter() >= vs && ppu.vcounter() <= (vs + 2))r |= 0x01;
|
||||||
|
|
||||||
|
//hblank
|
||||||
|
if(ppu.hcounter() <= 2 || ppu.hcounter() >= 1096)r |= 0x40;
|
||||||
|
|
||||||
|
//vblank
|
||||||
|
if(ppu.vcounter() >= vs)r |= 0x80;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDIO
|
||||||
|
uint8 sCPU::mmio_r4213() {
|
||||||
|
return status.pio;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDDIVL
|
||||||
|
uint8 sCPU::mmio_r4214() {
|
||||||
|
if(status.alu_lock) return 0;
|
||||||
|
return status.r4214;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDDIVH
|
||||||
|
uint8 sCPU::mmio_r4215() {
|
||||||
|
if(status.alu_lock) return 0;
|
||||||
|
return status.r4214 >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDMPYL
|
||||||
|
uint8 sCPU::mmio_r4216() {
|
||||||
|
if(status.alu_lock) return 0;
|
||||||
|
return status.r4216;
|
||||||
|
}
|
||||||
|
|
||||||
|
//RDMPYH
|
||||||
|
uint8 sCPU::mmio_r4217() {
|
||||||
|
if(status.alu_lock) return 0;
|
||||||
|
return status.r4216 >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: handle reads during joypad polling (v=225-227)
|
||||||
|
uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
|
||||||
|
uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
|
||||||
|
uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
|
||||||
|
uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
|
||||||
|
uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
|
||||||
|
uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
|
||||||
|
uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
|
||||||
|
uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
|
||||||
|
|
||||||
|
//DMAPx
|
||||||
|
uint8 sCPU::mmio_r43x0(uint8 i) {
|
||||||
|
return channel[i].dmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
//BBADx
|
||||||
|
uint8 sCPU::mmio_r43x1(uint8 i) {
|
||||||
|
return channel[i].destaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1TxL
|
||||||
|
uint8 sCPU::mmio_r43x2(uint8 i) {
|
||||||
|
return channel[i].srcaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1TxH
|
||||||
|
uint8 sCPU::mmio_r43x3(uint8 i) {
|
||||||
|
return channel[i].srcaddr >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1Bx
|
||||||
|
uint8 sCPU::mmio_r43x4(uint8 i) {
|
||||||
|
return channel[i].srcbank;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASxL
|
||||||
|
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||||
|
uint8 sCPU::mmio_r43x5(uint8 i) {
|
||||||
|
return channel[i].xfersize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASxH
|
||||||
|
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||||
|
uint8 sCPU::mmio_r43x6(uint8 i) {
|
||||||
|
return channel[i].xfersize >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASBx
|
||||||
|
uint8 sCPU::mmio_r43x7(uint8 i) {
|
||||||
|
return channel[i].hdma_ibank;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A2AxL
|
||||||
|
uint8 sCPU::mmio_r43x8(uint8 i) {
|
||||||
|
return channel[i].hdma_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A2AxH
|
||||||
|
uint8 sCPU::mmio_r43x9(uint8 i) {
|
||||||
|
return channel[i].hdma_addr >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NTRLx
|
||||||
|
uint8 sCPU::mmio_r43xa(uint8 i) {
|
||||||
|
return channel[i].hdma_line_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//???
|
||||||
|
uint8 sCPU::mmio_r43xb(uint8 i) {
|
||||||
|
return channel[i].unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DMAPx
|
||||||
|
void sCPU::mmio_w43x0(uint8 i, uint8 data) {
|
||||||
|
channel[i].dmap = data;
|
||||||
|
channel[i].direction = !!(data & 0x80);
|
||||||
|
channel[i].hdma_indirect = !!(data & 0x40);
|
||||||
|
channel[i].reversexfer = !!(data & 0x10);
|
||||||
|
channel[i].fixedxfer = !!(data & 0x08);
|
||||||
|
channel[i].xfermode = data & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DDBADx
|
||||||
|
void sCPU::mmio_w43x1(uint8 i, uint8 data) {
|
||||||
|
channel[i].destaddr = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1TxL
|
||||||
|
void sCPU::mmio_w43x2(uint8 i, uint8 data) {
|
||||||
|
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1TxH
|
||||||
|
void sCPU::mmio_w43x3(uint8 i, uint8 data) {
|
||||||
|
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//A1Bx
|
||||||
|
void sCPU::mmio_w43x4(uint8 i, uint8 data) {
|
||||||
|
channel[i].srcbank = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASxL
|
||||||
|
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||||
|
void sCPU::mmio_w43x5(uint8 i, uint8 data) {
|
||||||
|
channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASxH
|
||||||
|
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||||
|
void sCPU::mmio_w43x6(uint8 i, uint8 data) {
|
||||||
|
channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//DASBx
|
||||||
|
void sCPU::mmio_w43x7(uint8 i, uint8 data) {
|
||||||
|
channel[i].hdma_ibank = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//A2AxL
|
||||||
|
void sCPU::mmio_w43x8(uint8 i, uint8 data) {
|
||||||
|
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//A2AxH
|
||||||
|
void sCPU::mmio_w43x9(uint8 i, uint8 data) {
|
||||||
|
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//NTRLx
|
||||||
|
void sCPU::mmio_w43xa(uint8 i, uint8 data) {
|
||||||
|
channel[i].hdma_line_counter = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//???
|
||||||
|
void sCPU::mmio_w43xb(uint8 i, uint8 data) {
|
||||||
|
channel[i].unknown = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::mmio_power() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::mmio_reset() {
|
||||||
|
//$2181-$2183
|
||||||
|
status.wram_addr = 0x000000;
|
||||||
|
|
||||||
|
//$4016-$4017
|
||||||
|
status.joypad_strobe_latch = 0;
|
||||||
|
status.joypad1_bits = ~0;
|
||||||
|
status.joypad2_bits = ~0;
|
||||||
|
|
||||||
|
//$4200
|
||||||
|
status.nmi_enabled = false;
|
||||||
|
status.hirq_enabled = false;
|
||||||
|
status.virq_enabled = false;
|
||||||
|
status.auto_joypad_poll = false;
|
||||||
|
|
||||||
|
//$4201
|
||||||
|
status.pio = 0xff;
|
||||||
|
|
||||||
|
//$4202-$4203
|
||||||
|
status.mul_a = 0xff;
|
||||||
|
status.mul_b = 0xff;
|
||||||
|
|
||||||
|
//$4204-$4206
|
||||||
|
status.div_a = 0xffff;
|
||||||
|
status.div_b = 0xff;
|
||||||
|
|
||||||
|
//$4207-$420a
|
||||||
|
status.hirq_pos = 0x01ff;
|
||||||
|
status.virq_pos = 0x01ff;
|
||||||
|
|
||||||
|
//$4214-$4217
|
||||||
|
status.r4214 = 0x0000;
|
||||||
|
status.r4216 = 0x0000;
|
||||||
|
|
||||||
|
//$4218-$421f
|
||||||
|
status.joy1l = 0x00;
|
||||||
|
status.joy1h = 0x00;
|
||||||
|
status.joy2l = 0x00;
|
||||||
|
status.joy2h = 0x00;
|
||||||
|
status.joy3l = 0x00;
|
||||||
|
status.joy3h = 0x00;
|
||||||
|
status.joy4l = 0x00;
|
||||||
|
status.joy4h = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 sCPU::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
//APU
|
||||||
|
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||||
|
scheduler.sync_cpusmp();
|
||||||
|
return smp.port_read(addr & 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//DMA
|
||||||
|
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||||
|
unsigned i = (addr >> 4) & 7;
|
||||||
|
switch(addr & 0xf) {
|
||||||
|
case 0x0: return mmio_r43x0(i);
|
||||||
|
case 0x1: return mmio_r43x1(i);
|
||||||
|
case 0x2: return mmio_r43x2(i);
|
||||||
|
case 0x3: return mmio_r43x3(i);
|
||||||
|
case 0x4: return mmio_r43x4(i);
|
||||||
|
case 0x5: return mmio_r43x5(i);
|
||||||
|
case 0x6: return mmio_r43x6(i);
|
||||||
|
case 0x7: return mmio_r43x7(i);
|
||||||
|
case 0x8: return mmio_r43x8(i);
|
||||||
|
case 0x9: return mmio_r43x9(i);
|
||||||
|
case 0xa: return mmio_r43xa(i);
|
||||||
|
case 0xb: return mmio_r43xb(i);
|
||||||
|
case 0xc: return regs.mdr; //unmapped
|
||||||
|
case 0xd: return regs.mdr; //unmapped
|
||||||
|
case 0xe: return regs.mdr; //unmapped
|
||||||
|
case 0xf: return mmio_r43xb(i); //mirror of $43xb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2180: return mmio_r2180();
|
||||||
|
case 0x4016: return mmio_r4016();
|
||||||
|
case 0x4017: return mmio_r4017();
|
||||||
|
case 0x4210: return mmio_r4210();
|
||||||
|
case 0x4211: return mmio_r4211();
|
||||||
|
case 0x4212: return mmio_r4212();
|
||||||
|
case 0x4213: return mmio_r4213();
|
||||||
|
case 0x4214: return mmio_r4214();
|
||||||
|
case 0x4215: return mmio_r4215();
|
||||||
|
case 0x4216: return mmio_r4216();
|
||||||
|
case 0x4217: return mmio_r4217();
|
||||||
|
case 0x4218: return mmio_r4218();
|
||||||
|
case 0x4219: return mmio_r4219();
|
||||||
|
case 0x421a: return mmio_r421a();
|
||||||
|
case 0x421b: return mmio_r421b();
|
||||||
|
case 0x421c: return mmio_r421c();
|
||||||
|
case 0x421d: return mmio_r421d();
|
||||||
|
case 0x421e: return mmio_r421e();
|
||||||
|
case 0x421f: return mmio_r421f();
|
||||||
|
}
|
||||||
|
|
||||||
|
return regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
//APU
|
||||||
|
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
|
||||||
|
scheduler.sync_cpusmp();
|
||||||
|
port_write(addr & 3, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DMA
|
||||||
|
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||||
|
unsigned i = (addr >> 4) & 7;
|
||||||
|
switch(addr & 0xf) {
|
||||||
|
case 0x0: mmio_w43x0(i, data); return;
|
||||||
|
case 0x1: mmio_w43x1(i, data); return;
|
||||||
|
case 0x2: mmio_w43x2(i, data); return;
|
||||||
|
case 0x3: mmio_w43x3(i, data); return;
|
||||||
|
case 0x4: mmio_w43x4(i, data); return;
|
||||||
|
case 0x5: mmio_w43x5(i, data); return;
|
||||||
|
case 0x6: mmio_w43x6(i, data); return;
|
||||||
|
case 0x7: mmio_w43x7(i, data); return;
|
||||||
|
case 0x8: mmio_w43x8(i, data); return;
|
||||||
|
case 0x9: mmio_w43x9(i, data); return;
|
||||||
|
case 0xa: mmio_w43xa(i, data); return;
|
||||||
|
case 0xb: mmio_w43xb(i, data); return;
|
||||||
|
case 0xc: return; //unmapped
|
||||||
|
case 0xd: return; //unmapped
|
||||||
|
case 0xe: return; //unmapped
|
||||||
|
case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2180: mmio_w2180(data); return;
|
||||||
|
case 0x2181: mmio_w2181(data); return;
|
||||||
|
case 0x2182: mmio_w2182(data); return;
|
||||||
|
case 0x2183: mmio_w2183(data); return;
|
||||||
|
case 0x4016: mmio_w4016(data); return;
|
||||||
|
case 0x4017: return; //unmapped
|
||||||
|
case 0x4200: mmio_w4200(data); return;
|
||||||
|
case 0x4201: mmio_w4201(data); return;
|
||||||
|
case 0x4202: mmio_w4202(data); return;
|
||||||
|
case 0x4203: mmio_w4203(data); return;
|
||||||
|
case 0x4204: mmio_w4204(data); return;
|
||||||
|
case 0x4205: mmio_w4205(data); return;
|
||||||
|
case 0x4206: mmio_w4206(data); return;
|
||||||
|
case 0x4207: mmio_w4207(data); return;
|
||||||
|
case 0x4208: mmio_w4208(data); return;
|
||||||
|
case 0x4209: mmio_w4209(data); return;
|
||||||
|
case 0x420a: mmio_w420a(data); return;
|
||||||
|
case 0x420b: mmio_w420b(data); return;
|
||||||
|
case 0x420c: mmio_w420c(data); return;
|
||||||
|
case 0x420d: mmio_w420d(data); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ifdef SCPU_CPP
|
||||||
71
bsnes/cpu/scpu/mmio/mmio.hpp
Executable file
71
bsnes/cpu/scpu/mmio/mmio.hpp
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
void mmio_power();
|
||||||
|
void mmio_reset();
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8 pio();
|
||||||
|
bool joylatch();
|
||||||
|
|
||||||
|
uint8 mmio_r2180();
|
||||||
|
uint8 mmio_r4016();
|
||||||
|
uint8 mmio_r4017();
|
||||||
|
uint8 mmio_r4210();
|
||||||
|
uint8 mmio_r4211();
|
||||||
|
uint8 mmio_r4212();
|
||||||
|
uint8 mmio_r4213();
|
||||||
|
uint8 mmio_r4214();
|
||||||
|
uint8 mmio_r4215();
|
||||||
|
uint8 mmio_r4216();
|
||||||
|
uint8 mmio_r4217();
|
||||||
|
uint8 mmio_r4218();
|
||||||
|
uint8 mmio_r4219();
|
||||||
|
uint8 mmio_r421a();
|
||||||
|
uint8 mmio_r421b();
|
||||||
|
uint8 mmio_r421c();
|
||||||
|
uint8 mmio_r421d();
|
||||||
|
uint8 mmio_r421e();
|
||||||
|
uint8 mmio_r421f();
|
||||||
|
uint8 mmio_r43x0(uint8 i);
|
||||||
|
uint8 mmio_r43x1(uint8 i);
|
||||||
|
uint8 mmio_r43x2(uint8 i);
|
||||||
|
uint8 mmio_r43x3(uint8 i);
|
||||||
|
uint8 mmio_r43x4(uint8 i);
|
||||||
|
uint8 mmio_r43x5(uint8 i);
|
||||||
|
uint8 mmio_r43x6(uint8 i);
|
||||||
|
uint8 mmio_r43x7(uint8 i);
|
||||||
|
uint8 mmio_r43x8(uint8 i);
|
||||||
|
uint8 mmio_r43x9(uint8 i);
|
||||||
|
uint8 mmio_r43xa(uint8 i);
|
||||||
|
uint8 mmio_r43xb(uint8 i);
|
||||||
|
|
||||||
|
void mmio_w2180(uint8 data);
|
||||||
|
void mmio_w2181(uint8 data);
|
||||||
|
void mmio_w2182(uint8 data);
|
||||||
|
void mmio_w2183(uint8 data);
|
||||||
|
void mmio_w4016(uint8 data);
|
||||||
|
void mmio_w4200(uint8 data);
|
||||||
|
void mmio_w4201(uint8 data);
|
||||||
|
void mmio_w4202(uint8 data);
|
||||||
|
void mmio_w4203(uint8 data);
|
||||||
|
void mmio_w4204(uint8 data);
|
||||||
|
void mmio_w4205(uint8 data);
|
||||||
|
void mmio_w4206(uint8 data);
|
||||||
|
void mmio_w4207(uint8 data);
|
||||||
|
void mmio_w4208(uint8 data);
|
||||||
|
void mmio_w4209(uint8 data);
|
||||||
|
void mmio_w420a(uint8 data);
|
||||||
|
void mmio_w420b(uint8 data);
|
||||||
|
void mmio_w420c(uint8 data);
|
||||||
|
void mmio_w420d(uint8 data);
|
||||||
|
void mmio_w43x0(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x1(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x2(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x3(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x4(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x5(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x6(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x7(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x8(uint8 i, uint8 data);
|
||||||
|
void mmio_w43x9(uint8 i, uint8 data);
|
||||||
|
void mmio_w43xa(uint8 i, uint8 data);
|
||||||
|
void mmio_w43xb(uint8 i, uint8 data);
|
||||||
61
bsnes/cpu/scpu/scpu.cpp
Executable file
61
bsnes/cpu/scpu/scpu.cpp
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define SCPU_CPP
|
||||||
|
|
||||||
|
#include <nall/priorityqueue.hpp>
|
||||||
|
priority_queue<unsigned> event(512, bind(&sCPU::queue_event, &cpu));
|
||||||
|
|
||||||
|
#include "core/core.cpp"
|
||||||
|
#include "dma/dma.cpp"
|
||||||
|
#include "memory/memory.cpp"
|
||||||
|
#include "mmio/mmio.cpp"
|
||||||
|
#include "timing/timing.cpp"
|
||||||
|
|
||||||
|
void sCPU::power() {
|
||||||
|
CPU::power();
|
||||||
|
|
||||||
|
regs.a = regs.x = regs.y = 0x0000;
|
||||||
|
regs.s = 0x01ff;
|
||||||
|
|
||||||
|
mmio_power();
|
||||||
|
dma_power();
|
||||||
|
timing_power();
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::reset() {
|
||||||
|
CPU::reset();
|
||||||
|
|
||||||
|
regs.pc.d = 0x000000;
|
||||||
|
regs.pc.l = bus.read(0xfffc);
|
||||||
|
regs.pc.h = bus.read(0xfffd);
|
||||||
|
|
||||||
|
//note: some registers are not fully reset by SNES
|
||||||
|
regs.x.h = 0x00;
|
||||||
|
regs.y.h = 0x00;
|
||||||
|
regs.s.h = 0x01;
|
||||||
|
regs.d = 0x0000;
|
||||||
|
regs.db = 0x00;
|
||||||
|
regs.p = 0x34;
|
||||||
|
regs.e = 1;
|
||||||
|
regs.mdr = 0x00;
|
||||||
|
|
||||||
|
status.wai_lock = false;
|
||||||
|
status.interrupt_pending = false;
|
||||||
|
status.interrupt_vector = 0xfffc; //reset vector address
|
||||||
|
|
||||||
|
mmio_reset();
|
||||||
|
dma_reset();
|
||||||
|
timing_reset();
|
||||||
|
|
||||||
|
apu_port[0] = 0x00;
|
||||||
|
apu_port[1] = 0x00;
|
||||||
|
apu_port[2] = 0x00;
|
||||||
|
apu_port[3] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
sCPU::sCPU() {
|
||||||
|
}
|
||||||
|
|
||||||
|
sCPU::~sCPU() {
|
||||||
|
}
|
||||||
94
bsnes/cpu/scpu/scpu.hpp
Executable file
94
bsnes/cpu/scpu/scpu.hpp
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
class sCPU : public CPU {
|
||||||
|
public:
|
||||||
|
void enter();
|
||||||
|
|
||||||
|
#include "core/core.hpp"
|
||||||
|
#include "dma/dma.hpp"
|
||||||
|
#include "memory/memory.hpp"
|
||||||
|
#include "mmio/mmio.hpp"
|
||||||
|
#include "timing/timing.hpp"
|
||||||
|
|
||||||
|
enum DmaState { DmaInactive, DmaRun, DmaCpuSync };
|
||||||
|
|
||||||
|
struct {
|
||||||
|
//core
|
||||||
|
uint8 opcode;
|
||||||
|
bool in_opcode;
|
||||||
|
|
||||||
|
bool wai_lock;
|
||||||
|
bool interrupt_pending;
|
||||||
|
uint16 interrupt_vector;
|
||||||
|
|
||||||
|
unsigned clock_count;
|
||||||
|
unsigned line_clocks;
|
||||||
|
|
||||||
|
//timing
|
||||||
|
bool irq_lock;
|
||||||
|
bool alu_lock;
|
||||||
|
unsigned dram_refresh_position;
|
||||||
|
|
||||||
|
bool nmi_valid;
|
||||||
|
bool nmi_line;
|
||||||
|
bool nmi_transition;
|
||||||
|
bool nmi_pending;
|
||||||
|
bool nmi_hold;
|
||||||
|
|
||||||
|
bool irq_valid;
|
||||||
|
bool irq_line;
|
||||||
|
bool irq_transition;
|
||||||
|
bool irq_pending;
|
||||||
|
bool irq_hold;
|
||||||
|
|
||||||
|
//DMA
|
||||||
|
unsigned dma_counter;
|
||||||
|
unsigned dma_clocks;
|
||||||
|
bool dma_pending;
|
||||||
|
bool hdma_pending;
|
||||||
|
bool hdma_mode; //0 = init, 1 = run
|
||||||
|
DmaState dma_state;
|
||||||
|
|
||||||
|
//MMIO
|
||||||
|
|
||||||
|
//$2181-$2183
|
||||||
|
uint32 wram_addr;
|
||||||
|
|
||||||
|
//$4016-$4017
|
||||||
|
bool joypad_strobe_latch;
|
||||||
|
uint32 joypad1_bits;
|
||||||
|
uint32 joypad2_bits;
|
||||||
|
|
||||||
|
//$4200
|
||||||
|
bool nmi_enabled;
|
||||||
|
bool hirq_enabled, virq_enabled;
|
||||||
|
bool auto_joypad_poll;
|
||||||
|
|
||||||
|
//$4201
|
||||||
|
uint8 pio;
|
||||||
|
|
||||||
|
//$4202-$4203
|
||||||
|
uint8 mul_a, mul_b;
|
||||||
|
|
||||||
|
//$4204-$4206
|
||||||
|
uint16 div_a;
|
||||||
|
uint8 div_b;
|
||||||
|
|
||||||
|
//$4207-$420a
|
||||||
|
uint16 hirq_pos, virq_pos;
|
||||||
|
|
||||||
|
//$4214-$4217
|
||||||
|
uint16 r4214;
|
||||||
|
uint16 r4216;
|
||||||
|
|
||||||
|
//$4218-$421f
|
||||||
|
uint8 joy1l, joy1h;
|
||||||
|
uint8 joy2l, joy2h;
|
||||||
|
uint8 joy3l, joy3h;
|
||||||
|
uint8 joy4l, joy4h;
|
||||||
|
} status;
|
||||||
|
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
sCPU();
|
||||||
|
~sCPU();
|
||||||
|
};
|
||||||
35
bsnes/cpu/scpu/timing/event.cpp
Executable file
35
bsnes/cpu/scpu/timing/event.cpp
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
void sCPU::queue_event(unsigned id) {
|
||||||
|
switch(id) {
|
||||||
|
//interrupts triggered during (H)DMA do not trigger immediately after
|
||||||
|
case EventIrqLockRelease: {
|
||||||
|
status.irq_lock = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//ALU multiplication / division results are not immediately calculated;
|
||||||
|
//the exact formula for the calculations are unknown, but this lock at least
|
||||||
|
//allows emulation to avoid returning to fully computed results too soon.
|
||||||
|
case EventAluLockRelease: {
|
||||||
|
status.alu_lock = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//S-CPU WRAM consists of two 64kbyte DRAM chips, which must be refreshed
|
||||||
|
//once per scanline to avoid memory decay.
|
||||||
|
case EventDramRefresh: {
|
||||||
|
add_clocks(40);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//HDMA init routine; occurs once per frame
|
||||||
|
case EventHdmaInit: {
|
||||||
|
cycle_edge_state |= EventFlagHdmaInit;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//HDMA run routine; occurs once per scanline
|
||||||
|
case EventHdmaRun: {
|
||||||
|
cycle_edge_state |= EventFlagHdmaRun;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
107
bsnes/cpu/scpu/timing/irq.cpp
Executable file
107
bsnes/cpu/scpu/timing/irq.cpp
Executable file
@ -0,0 +1,107 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
//called once every four clock cycles;
|
||||||
|
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
|
||||||
|
//
|
||||||
|
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
|
||||||
|
//it is used to emulate hardware communication delay between opcode and interrupt units.
|
||||||
|
void sCPU::poll_interrupts() {
|
||||||
|
//NMI hold
|
||||||
|
if(status.nmi_hold) {
|
||||||
|
status.nmi_hold = false;
|
||||||
|
if(status.nmi_enabled) status.nmi_transition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NMI test
|
||||||
|
bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240));
|
||||||
|
if(!status.nmi_valid && nmi_valid) {
|
||||||
|
//0->1 edge sensitive transition
|
||||||
|
status.nmi_line = true;
|
||||||
|
status.nmi_hold = true; //hold /NMI for four cycles
|
||||||
|
} else if(status.nmi_valid && !nmi_valid) {
|
||||||
|
//1->0 edge sensitive transition
|
||||||
|
status.nmi_line = false;
|
||||||
|
}
|
||||||
|
status.nmi_valid = nmi_valid;
|
||||||
|
|
||||||
|
//IRQ hold
|
||||||
|
status.irq_hold = false;
|
||||||
|
if(status.irq_line) {
|
||||||
|
if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//IRQ test
|
||||||
|
bool irq_valid = (status.virq_enabled || status.hirq_enabled);
|
||||||
|
if(irq_valid) {
|
||||||
|
if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos))
|
||||||
|
|| (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4)
|
||||||
|
|| (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field
|
||||||
|
) irq_valid = false;
|
||||||
|
}
|
||||||
|
if(!status.irq_valid && irq_valid) {
|
||||||
|
//0->1 edge sensitive transition
|
||||||
|
status.irq_line = true;
|
||||||
|
status.irq_hold = true; //hold /IRQ for four cycles
|
||||||
|
}
|
||||||
|
status.irq_valid = irq_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::nmitimen_update(uint8 data) {
|
||||||
|
bool nmi_enabled = status.nmi_enabled;
|
||||||
|
bool virq_enabled = status.virq_enabled;
|
||||||
|
bool hirq_enabled = status.hirq_enabled;
|
||||||
|
status.nmi_enabled = data & 0x80;
|
||||||
|
status.virq_enabled = data & 0x20;
|
||||||
|
status.hirq_enabled = data & 0x10;
|
||||||
|
|
||||||
|
//0->1 edge sensitive transition
|
||||||
|
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
|
||||||
|
status.nmi_transition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//?->1 level sensitive transition
|
||||||
|
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
|
||||||
|
status.irq_transition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!status.virq_enabled && !status.hirq_enabled) {
|
||||||
|
status.irq_line = false;
|
||||||
|
status.irq_transition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.irq_lock = true;
|
||||||
|
event.enqueue(2, EventIrqLockRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sCPU::rdnmi() {
|
||||||
|
bool result = status.nmi_line;
|
||||||
|
if(!status.nmi_hold) {
|
||||||
|
status.nmi_line = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sCPU::timeup() {
|
||||||
|
bool result = status.irq_line;
|
||||||
|
if(!status.irq_hold) {
|
||||||
|
status.irq_line = false;
|
||||||
|
status.irq_transition = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sCPU::nmi_test() {
|
||||||
|
if(!status.nmi_transition) return false;
|
||||||
|
status.nmi_transition = false;
|
||||||
|
status.wai_lock = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sCPU::irq_test() {
|
||||||
|
if(!status.irq_transition) return false;
|
||||||
|
status.irq_transition = false;
|
||||||
|
status.wai_lock = false;
|
||||||
|
return !regs.p.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
28
bsnes/cpu/scpu/timing/joypad.cpp
Executable file
28
bsnes/cpu/scpu/timing/joypad.cpp
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
void sCPU::run_auto_joypad_poll() {
|
||||||
|
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
|
||||||
|
for(unsigned i = 0; i < 16; i++) {
|
||||||
|
uint8 port0 = snes.input.port_read(0);
|
||||||
|
uint8 port1 = snes.input.port_read(1);
|
||||||
|
|
||||||
|
joy1 |= (port0 & 1) ? (0x8000 >> i) : 0;
|
||||||
|
joy2 |= (port1 & 1) ? (0x8000 >> i) : 0;
|
||||||
|
joy3 |= (port0 & 2) ? (0x8000 >> i) : 0;
|
||||||
|
joy4 |= (port1 & 2) ? (0x8000 >> i) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.joy1l = joy1;
|
||||||
|
status.joy1h = joy1 >> 8;
|
||||||
|
|
||||||
|
status.joy2l = joy2;
|
||||||
|
status.joy2h = joy2 >> 8;
|
||||||
|
|
||||||
|
status.joy3l = joy3;
|
||||||
|
status.joy3h = joy3 >> 8;
|
||||||
|
|
||||||
|
status.joy4l = joy4;
|
||||||
|
status.joy4h = joy4 >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
166
bsnes/cpu/scpu/timing/timing.cpp
Executable file
166
bsnes/cpu/scpu/timing/timing.cpp
Executable file
@ -0,0 +1,166 @@
|
|||||||
|
#ifdef SCPU_CPP
|
||||||
|
|
||||||
|
#include "event.cpp"
|
||||||
|
#include "irq.cpp"
|
||||||
|
#include "joypad.cpp"
|
||||||
|
|
||||||
|
unsigned sCPU::dma_counter() {
|
||||||
|
return (status.dma_counter + ppu.hcounter()) & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::add_clocks(unsigned clocks) {
|
||||||
|
event.tick(clocks);
|
||||||
|
unsigned ticks = clocks >> 1;
|
||||||
|
while(ticks--) {
|
||||||
|
ppu.tick();
|
||||||
|
if((ppu.hcounter() & 2) == 0) {
|
||||||
|
snes.input.tick();
|
||||||
|
} else {
|
||||||
|
poll_interrupts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scheduler.addclocks_cpu(clocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::scanline() {
|
||||||
|
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
||||||
|
status.line_clocks = ppu.lineclocks();
|
||||||
|
|
||||||
|
if(ppu.vcounter() == 0) {
|
||||||
|
//hdma init triggers once every frame
|
||||||
|
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dram refresh occurs once every scanline
|
||||||
|
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
|
||||||
|
event.enqueue(status.dram_refresh_position, EventDramRefresh);
|
||||||
|
|
||||||
|
//hdma triggers once every visible scanline
|
||||||
|
if(ppu.vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
|
||||||
|
event.enqueue(1104, EventHdmaRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.auto_joypad_poll == true && ppu.vcounter() == (ppu.overscan() == false ? 227 : 242)) {
|
||||||
|
snes.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) {
|
||||||
|
switch(bit::lowest(cycle_edge_state)) {
|
||||||
|
case EventFlagHdmaInit: {
|
||||||
|
hdma_init_reset();
|
||||||
|
if(hdma_enabled_channels()) {
|
||||||
|
status.hdma_pending = true;
|
||||||
|
status.hdma_mode = 0;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case EventFlagHdmaRun: {
|
||||||
|
if(hdma_active_channels()) {
|
||||||
|
status.hdma_pending = true;
|
||||||
|
status.hdma_mode = 1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle_edge_state = bit::clear_lowest(cycle_edge_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
//H/DMA pending && DMA inactive?
|
||||||
|
//.. Run one full CPU cycle
|
||||||
|
//.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
|
||||||
|
//.. DMA pending && DMA enabled ? DMA sync + DMA run
|
||||||
|
//.... HDMA during DMA && HDMA enabled ? DMA sync + HDMA run
|
||||||
|
//.. Run one bus CPU cycle
|
||||||
|
//.. CPU sync
|
||||||
|
|
||||||
|
if(status.dma_state == DmaRun) {
|
||||||
|
if(status.hdma_pending) {
|
||||||
|
status.hdma_pending = false;
|
||||||
|
if(hdma_enabled_channels()) {
|
||||||
|
dma_add_clocks(8 - dma_counter()); //DMA sync
|
||||||
|
status.hdma_mode == 0 ? hdma_init() : hdma_run();
|
||||||
|
if(!dma_enabled_channels()) status.dma_state = DmaCpuSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.dma_pending) {
|
||||||
|
status.dma_pending = false;
|
||||||
|
if(dma_enabled_channels()) {
|
||||||
|
dma_add_clocks(8 - dma_counter()); //DMA sync
|
||||||
|
dma_run();
|
||||||
|
status.dma_state = DmaCpuSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.dma_state == DmaInactive) {
|
||||||
|
if(status.dma_pending || status.hdma_pending) {
|
||||||
|
status.dma_clocks = 0;
|
||||||
|
status.dma_state = DmaRun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//used to test for NMI/IRQ, which can trigger on the edge of every opcode.
|
||||||
|
//test one cycle early to simulate two-stage pipeline of x816 CPU.
|
||||||
|
//
|
||||||
|
//status.irq_lock is used to simulate hardware delay before interrupts can
|
||||||
|
//trigger during certain events (immediately after DMA, writes to $4200, etc)
|
||||||
|
void sCPU::last_cycle() {
|
||||||
|
if(!status.irq_lock) {
|
||||||
|
status.nmi_pending |= nmi_test();
|
||||||
|
status.irq_pending |= irq_test();
|
||||||
|
|
||||||
|
status.interrupt_pending = (status.nmi_pending || status.irq_pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::timing_power() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void sCPU::timing_reset() {
|
||||||
|
event.reset();
|
||||||
|
|
||||||
|
status.clock_count = 0;
|
||||||
|
status.line_clocks = ppu.lineclocks();
|
||||||
|
|
||||||
|
status.irq_lock = false;
|
||||||
|
status.alu_lock = false;
|
||||||
|
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
|
||||||
|
event.enqueue(status.dram_refresh_position, EventDramRefresh);
|
||||||
|
|
||||||
|
status.nmi_valid = false;
|
||||||
|
status.nmi_line = false;
|
||||||
|
status.nmi_transition = false;
|
||||||
|
status.nmi_pending = false;
|
||||||
|
status.nmi_hold = false;
|
||||||
|
|
||||||
|
status.irq_valid = false;
|
||||||
|
status.irq_line = false;
|
||||||
|
status.irq_transition = false;
|
||||||
|
status.irq_pending = false;
|
||||||
|
status.irq_hold = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
41
bsnes/cpu/scpu/timing/timing.hpp
Executable file
41
bsnes/cpu/scpu/timing/timing.hpp
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
enum {
|
||||||
|
EventNone,
|
||||||
|
EventIrqLockRelease,
|
||||||
|
EventAluLockRelease,
|
||||||
|
EventDramRefresh,
|
||||||
|
EventHdmaInit,
|
||||||
|
EventHdmaRun,
|
||||||
|
|
||||||
|
//cycle edge
|
||||||
|
EventFlagHdmaInit = 1 << 0,
|
||||||
|
EventFlagHdmaRun = 1 << 1,
|
||||||
|
};
|
||||||
|
unsigned cycle_edge_state;
|
||||||
|
|
||||||
|
//timing.cpp
|
||||||
|
unsigned dma_counter();
|
||||||
|
|
||||||
|
void add_clocks(unsigned clocks);
|
||||||
|
void scanline();
|
||||||
|
|
||||||
|
alwaysinline void precycle_edge();
|
||||||
|
alwaysinline void cycle_edge();
|
||||||
|
void last_cycle();
|
||||||
|
|
||||||
|
void timing_power();
|
||||||
|
void timing_reset();
|
||||||
|
|
||||||
|
//irq.cpp
|
||||||
|
alwaysinline void poll_interrupts();
|
||||||
|
void nmitimen_update(uint8 data);
|
||||||
|
bool rdnmi();
|
||||||
|
bool timeup();
|
||||||
|
|
||||||
|
alwaysinline bool nmi_test();
|
||||||
|
alwaysinline bool irq_test();
|
||||||
|
|
||||||
|
//joypad.cpp
|
||||||
|
void run_auto_joypad_poll();
|
||||||
|
|
||||||
|
//event.cpp
|
||||||
|
void queue_event(unsigned); //priorityqueue callback function
|
||||||
9
bsnes/data/bsnes.Manifest
Executable file
9
bsnes/data/bsnes.Manifest
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
||||||
8
bsnes/data/bsnes.desktop
Executable file
8
bsnes/data/bsnes.desktop
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=bsnes
|
||||||
|
Comment=SNES emulator
|
||||||
|
Exec=bsnes
|
||||||
|
Icon=bsnes
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Game;Emulator;
|
||||||
BIN
bsnes/data/bsnes.ico
Executable file
BIN
bsnes/data/bsnes.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
bsnes/data/bsnes.png
Executable file
BIN
bsnes/data/bsnes.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
81
bsnes/data/documentation.html
Executable file
81
bsnes/data/documentation.html
Executable file
@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<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.
|
||||||
|
<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>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
In multi-user mode, configuration data is stored inside the user's home
|
||||||
|
directory. On Windows, this is located at "%APPDATA%/.bsnes". On other operating
|
||||||
|
systems, this is located at "~/.bsnes".<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
To enable single-user mode, create a blank "bsnes.cfg" file inside the same
|
||||||
|
folder as the bsnes executable. bsnes will then use this file to store
|
||||||
|
configuration data.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>Supported Filetypes</u></h2><br>
|
||||||
|
|
||||||
|
<b>SFC, SMC, SWC, FIG:</b> SNES cartridge — ROM image.<br>
|
||||||
|
<b>BS:</b> Satellaview BS-X flash cartridge — EEPROM image.<br>
|
||||||
|
<b>ST:</b> Sufami Turbo cartridge — ROM image.<br>
|
||||||
|
<b>SRM, PSR:</b> non-volatile memory, often used to save game data — (P)SRAM image.<br>
|
||||||
|
<b>RTC:</b> real-time clock non-volatile memory.<br>
|
||||||
|
<b>UPS:</b> patch data, used to dynamically modify cartridge of same base filename upon load.<br>
|
||||||
|
<b>CHT:</b> plain-text list of "Game Genie" / "Pro Action Replay" codes.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<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
|
||||||
|
implement support for savestate and/or rewind functionality.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>Netplay:</b> internet multiplay is not currently supported nor planned.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>Contributors</u></h2>
|
||||||
|
• Andreas Naive<br>
|
||||||
|
• anomie<br>
|
||||||
|
• Derrick Sobodash<br>
|
||||||
|
• DMV27<br>
|
||||||
|
• FirebrandX<br>
|
||||||
|
• FitzRoy<br>
|
||||||
|
• GIGO<br>
|
||||||
|
• Jonas Quinn<br>
|
||||||
|
• kode54<br>
|
||||||
|
• krom<br>
|
||||||
|
• Matthew Callis<br>
|
||||||
|
• Nach<br>
|
||||||
|
• neviksti<br>
|
||||||
|
• Overload<br>
|
||||||
|
• RedDwarf<br>
|
||||||
|
• Richard Bannister<br>
|
||||||
|
• Shay Green<br>
|
||||||
|
• tetsuo55<br>
|
||||||
|
• TRAC<br>
|
||||||
|
• zones<br>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
bsnes/data/joypad.png
Executable file
BIN
bsnes/data/joypad.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
87
bsnes/data/license.html
Executable file
87
bsnes/data/license.html
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>bsnes™ Reference License</h1><br>
|
||||||
|
<b>Copyright © 2004–2009 byuu<br>
|
||||||
|
All rights reserved</b>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>1. Definitions</u></h2><br>
|
||||||
|
|
||||||
|
The terms "reproduce", "reproduction", "distribute" and "distribution" have the
|
||||||
|
same meaning here as under U.S. copyright law.<br><br>
|
||||||
|
|
||||||
|
"The software" means this software package as a whole, including, but not
|
||||||
|
limited to, this license, binaries, source code, documentation, and data.<br><br>
|
||||||
|
|
||||||
|
"You" means the licensee of the software.<br><br>
|
||||||
|
|
||||||
|
"The licensor" means the copyright holder of the software, byuu.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>2. Grant of Rights</u></h2><br>
|
||||||
|
|
||||||
|
Subject to the terms of this license, the licensor grants you a
|
||||||
|
non-transferable, non-exclusive, worldwide, royalty-free copyright license to
|
||||||
|
reproduce the software for non-commercial use only, provided the software
|
||||||
|
remains unmodified, and there is no charge for the software itself, nor for the
|
||||||
|
medium upon which the software is distributed. The reproduction of modified or
|
||||||
|
derivative works of the software is strictly prohibited without the express
|
||||||
|
consent of the licensor.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>3. Limitations</u></h2><br>
|
||||||
|
|
||||||
|
This license does not grant you any rights to use the licensor's name, logo or
|
||||||
|
trademarks.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
The software is provided "as is", and any express or implied warranties,
|
||||||
|
including, but not limited to, the implied warranties of merchantability and
|
||||||
|
fitness for a particular purpose are disclaimed. In no event shall the licensor
|
||||||
|
be liable for any direct, indirect, incidental, special, exemplary, or
|
||||||
|
consequential damages (including, but not limited to, procurement of sbustitute
|
||||||
|
goods or services; loss of use, data, or profits; or business interruption)
|
||||||
|
however caused and on any theory of liability, whether in contract, strict
|
||||||
|
liability, or tort (including negligence or otherwise) arising in any way out of
|
||||||
|
the use of the software, even if advised of the possibility of such damage.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
In the event that this license is determined to be invalid or unenforceable, the
|
||||||
|
Grant of Rights will become null and void, and no rights shall be granted to the
|
||||||
|
licensee, within the scope of U.S. copyright law.
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><u>4. Exemptions</u></h2><br>
|
||||||
|
|
||||||
|
The software includes the work of other copyrights holders, which is licensed
|
||||||
|
under different agreements, and exempt from this license. Below is a complete
|
||||||
|
list of all such software, and their respective copyright holders and licenses.
|
||||||
|
Note that explicit permission has been granted to the licensor to use included
|
||||||
|
software which is ordinarily not compatible with this license, such as the GPL.
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<table border="1" cellpadding="3">
|
||||||
|
<tr><td><b>Name</b></td><td><b>License</b></td><td><b>Author(s)</b></td></tr>
|
||||||
|
|
||||||
|
<tr><td>Cx4 emulator</td><td></td><td>anomie, Kris Bleakley, Nach, zsKnight</td></tr>
|
||||||
|
<tr><td>DSP-1 emulator</td><td></td><td>Andreas Naive, John Weidman, Kris Bleakley, neviksti</td></tr>
|
||||||
|
<tr><td>DSP-2 emulator</td><td></td><td>Kris Bleakley</td></tr>
|
||||||
|
<tr><td>DSP-3 emulator</td><td></td><td>John Weidman, Kris Bleakley, Lancer, z80 gaiden</td></tr>
|
||||||
|
<tr><td>DSP-4 emulator</td><td></td><td>Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden</td></tr>
|
||||||
|
<tr><td>S-DD1 decompressor</td><td>Public Domain</td><td>Andreas Naive</td></tr>
|
||||||
|
<tr><td>S-DSP emulator</td><td>LGPL 2.1</td><td>Shay Green</td></tr>
|
||||||
|
<tr><td>SPC7110 decompressor</td><td>Public Domain</td><td>neviksti</td></tr>
|
||||||
|
<tr><td>ST-0010 emulator</td><td></td><td>Feather, John Weidman, Kris Bleakley, Matthew Kendora</td></tr>
|
||||||
|
|
||||||
|
<tr><td>Qt toolkit</td><td>LGPL 2.1</td><td>Nokia</td></tr>
|
||||||
|
<tr><td>HQ2x filter</td><td>LGPL 2.1</td><td>MaxST</td></tr>
|
||||||
|
<tr><td>JMA decompressor</td><td>GPL 2</td><td>NSRT team</td></tr>
|
||||||
|
<tr><td>NTSC filter</td><td>LGPL 2.1</td><td>Shay Green</td></tr>
|
||||||
|
<tr><td>zlib decompressor</td><td>zlib license</td><td>zlib team</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
bsnes/data/logo.png
Executable file
BIN
bsnes/data/logo.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
588
bsnes/dsp/adsp/adsp.cpp
Executable file
588
bsnes/dsp/adsp/adsp.cpp
Executable file
@ -0,0 +1,588 @@
|
|||||||
|
#include <../base.hpp>
|
||||||
|
#define ADSP_CPP
|
||||||
|
|
||||||
|
#include "adsp_tables.cpp"
|
||||||
|
|
||||||
|
void aDSP::enter() { loop:
|
||||||
|
run();
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 aDSP::readb(uint16 addr) {
|
||||||
|
return spcram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::writeb(uint16 addr, uint8 data) {
|
||||||
|
spcram[addr] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 aDSP::readw(uint16 addr) {
|
||||||
|
return (readb(addr + 0)) | (readb(addr + 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::writew(uint16 addr, uint16 data) {
|
||||||
|
writeb(addr + 0, data);
|
||||||
|
writeb(addr + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 aDSP::read(uint8 addr) {
|
||||||
|
addr &= 127;
|
||||||
|
int v = addr >> 4;
|
||||||
|
int n = addr & 15;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||||
|
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||||
|
return voice[v].VOLL;
|
||||||
|
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||||
|
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||||
|
return voice[v].VOLR;
|
||||||
|
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||||
|
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||||
|
return voice[v].PITCH;
|
||||||
|
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||||
|
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||||
|
return voice[v].PITCH >> 8;
|
||||||
|
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||||
|
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||||
|
return voice[v].SRCN;
|
||||||
|
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||||
|
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||||
|
return voice[v].ADSR1;
|
||||||
|
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||||
|
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||||
|
return voice[v].ADSR2;
|
||||||
|
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||||
|
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||||
|
return voice[v].GAIN;
|
||||||
|
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||||
|
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||||
|
return voice[v].ENVX;
|
||||||
|
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||||
|
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||||
|
return voice[v].OUTX;
|
||||||
|
|
||||||
|
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||||
|
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||||
|
return status.FIR[v];
|
||||||
|
|
||||||
|
case 0x0c: return status.MVOLL;
|
||||||
|
case 0x1c: return status.MVOLR;
|
||||||
|
case 0x2c: return status.EVOLL;
|
||||||
|
case 0x3c: return status.EVOLR;
|
||||||
|
case 0x4c: return status.KON;
|
||||||
|
case 0x5c: return status.KOFF;
|
||||||
|
case 0x6c: return status.FLG;
|
||||||
|
case 0x7c: return status.ENDX;
|
||||||
|
|
||||||
|
case 0x0d: return status.EFB;
|
||||||
|
case 0x2d: return status.PMON;
|
||||||
|
case 0x3d: return status.NON;
|
||||||
|
case 0x4d: return status.EON;
|
||||||
|
case 0x5d: return status.DIR;
|
||||||
|
case 0x6d: return status.ESA;
|
||||||
|
case 0x7d: return status.EDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dspram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::write(uint8 addr, uint8 data) {
|
||||||
|
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||||
|
if(addr & 0x80)return;
|
||||||
|
|
||||||
|
int v = addr >> 4;
|
||||||
|
int n = addr & 15;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||||
|
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||||
|
voice[v].VOLL = data;
|
||||||
|
break;
|
||||||
|
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||||
|
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||||
|
voice[v].VOLR = data;
|
||||||
|
break;
|
||||||
|
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||||
|
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||||
|
voice[v].PITCH &= 0xff00;
|
||||||
|
voice[v].PITCH |= data;
|
||||||
|
break;
|
||||||
|
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||||
|
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||||
|
voice[v].PITCH &= 0x00ff;
|
||||||
|
voice[v].PITCH |= data << 8;
|
||||||
|
break;
|
||||||
|
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||||
|
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||||
|
voice[v].SRCN = data;
|
||||||
|
break;
|
||||||
|
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||||
|
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||||
|
voice[v].ADSR1 = data;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
break;
|
||||||
|
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||||
|
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||||
|
voice[v].ADSR2 = data;
|
||||||
|
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
|
||||||
|
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
break;
|
||||||
|
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||||
|
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||||
|
voice[v].GAIN = data;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
break;
|
||||||
|
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||||
|
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||||
|
voice[v].ENVX = data;
|
||||||
|
break;
|
||||||
|
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||||
|
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||||
|
voice[v].OUTX = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||||
|
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||||
|
status.FIR[v] = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0c: status.MVOLL = data; break;
|
||||||
|
case 0x1c: status.MVOLR = data; break;
|
||||||
|
case 0x2c: status.EVOLL = data; break;
|
||||||
|
case 0x3c: status.EVOLR = data; break;
|
||||||
|
|
||||||
|
case 0x4c:
|
||||||
|
status.KON = data;
|
||||||
|
status.kon = data;
|
||||||
|
break;
|
||||||
|
case 0x5c:
|
||||||
|
status.KOFF = data;
|
||||||
|
break;
|
||||||
|
case 0x6c:
|
||||||
|
status.FLG = data;
|
||||||
|
status.noise_rate = rate_table[data & 0x1f];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x7c:
|
||||||
|
//read-only register, writes clear all bits of ENDX
|
||||||
|
status.ENDX = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0d: status.EFB = data; break;
|
||||||
|
case 0x2d: status.PMON = data; break;
|
||||||
|
case 0x3d: status.NON = data; break;
|
||||||
|
case 0x4d: status.EON = data; break;
|
||||||
|
case 0x5d: status.DIR = data; break;
|
||||||
|
case 0x6d: status.ESA = data; break;
|
||||||
|
case 0x7d: status.EDL = data; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dspram[addr] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::power() {
|
||||||
|
spcram = r_smp->get_spcram_handle();
|
||||||
|
memset(dspram, 0x00, 128);
|
||||||
|
|
||||||
|
for(int v = 0; v < 8; v++) {
|
||||||
|
voice[v].VOLL = 0;
|
||||||
|
voice[v].VOLR = 0;
|
||||||
|
voice[v].PITCH = 0;
|
||||||
|
voice[v].SRCN = 0;
|
||||||
|
voice[v].ADSR1 = 0;
|
||||||
|
voice[v].ADSR2 = 0;
|
||||||
|
voice[v].GAIN = 0;
|
||||||
|
|
||||||
|
status.FIR[v] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.FLG = 0xe0;
|
||||||
|
status.MVOLL = status.MVOLR = 0;
|
||||||
|
status.EVOLL = status.EVOLR = 0;
|
||||||
|
status.ENDX = 0;
|
||||||
|
status.EFB = 0;
|
||||||
|
status.PMON = 0;
|
||||||
|
status.NON = 0;
|
||||||
|
status.EON = 0;
|
||||||
|
status.DIR = 0;
|
||||||
|
status.ESA = 0;
|
||||||
|
status.EDL = 0;
|
||||||
|
|
||||||
|
status.echo_length = 0;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::reset() {
|
||||||
|
status.KON = 0x00;
|
||||||
|
status.KOFF = 0x00;
|
||||||
|
status.FLG |= 0xe0;
|
||||||
|
|
||||||
|
status.kon = 0x00;
|
||||||
|
status.esa = 0x00;
|
||||||
|
|
||||||
|
status.noise_ctr = 0;
|
||||||
|
status.noise_rate = 0;
|
||||||
|
status.noise_sample = 0x4000;
|
||||||
|
|
||||||
|
status.echo_index = 0;
|
||||||
|
status.fir_buffer_index = 0;
|
||||||
|
|
||||||
|
for(int v = 0; v < 8; v++) {
|
||||||
|
voice[v].ENVX = 0;
|
||||||
|
voice[v].OUTX = 0;
|
||||||
|
|
||||||
|
voice[v].pitch_ctr = 0;
|
||||||
|
|
||||||
|
voice[v].brr_index = 0;
|
||||||
|
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||||
|
voice[v].brr_looped = false;
|
||||||
|
voice[v].brr_data[0] = 0;
|
||||||
|
voice[v].brr_data[1] = 0;
|
||||||
|
voice[v].brr_data[2] = 0;
|
||||||
|
voice[v].brr_data[3] = 0;
|
||||||
|
voice[v].brr_data_index = 0;
|
||||||
|
|
||||||
|
voice[v].envx = 0;
|
||||||
|
voice[v].env_ctr = 0;
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
voice[v].env_state = SILENCE;
|
||||||
|
voice[v].env_mode = DIRECT;
|
||||||
|
|
||||||
|
status.fir_buffer[0][v] = 0;
|
||||||
|
status.fir_buffer[1][v] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aDSP::run() {
|
||||||
|
uint8 pmon;
|
||||||
|
int32 sample;
|
||||||
|
int32 msamplel, msampler;
|
||||||
|
int32 esamplel, esampler;
|
||||||
|
int32 fir_samplel, fir_sampler;
|
||||||
|
pmon = status.PMON & ~status.NON & ~1;
|
||||||
|
|
||||||
|
if((dsp_counter++ & 1) == 0) {
|
||||||
|
for(uint v = 0; v < 8; v++) {
|
||||||
|
if(status.soft_reset()) {
|
||||||
|
if(voice[v].env_state != SILENCE) {
|
||||||
|
voice[v].env_state = SILENCE;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(status.KOFF & (1 << v)) {
|
||||||
|
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||||
|
voice[v].env_state = RELEASE;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(status.kon & (1 << v)) {
|
||||||
|
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||||
|
voice[v].brr_index = -9;
|
||||||
|
voice[v].brr_looped = false;
|
||||||
|
voice[v].brr_data[0] = 0;
|
||||||
|
voice[v].brr_data[1] = 0;
|
||||||
|
voice[v].brr_data[2] = 0;
|
||||||
|
voice[v].brr_data[3] = 0;
|
||||||
|
voice[v].envx = 0;
|
||||||
|
voice[v].env_state = ATTACK;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status.ENDX &= ~status.kon;
|
||||||
|
status.kon = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* update noise
|
||||||
|
*****/
|
||||||
|
status.noise_ctr += status.noise_rate;
|
||||||
|
if(status.noise_ctr >= 0x7800) {
|
||||||
|
status.noise_ctr -= 0x7800;
|
||||||
|
status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
msamplel = msampler = 0;
|
||||||
|
esamplel = esampler = 0;
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* process voice channels
|
||||||
|
*****/
|
||||||
|
for(int v = 0; v < 8; v++) {
|
||||||
|
if(voice[v].brr_index < -1) {
|
||||||
|
voice[v].brr_index++;
|
||||||
|
voice[v].OUTX = voice[v].outx = 0;
|
||||||
|
voice[v].ENVX = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(voice[v].brr_index >= 0) {
|
||||||
|
if(pmon & (1 << v)) {
|
||||||
|
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
|
||||||
|
} else {
|
||||||
|
voice[v].pitch_ctr += voice[v].pitch_rate();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
voice[v].pitch_ctr = 0x3000;
|
||||||
|
voice[v].brr_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* decode BRR samples
|
||||||
|
*****/
|
||||||
|
while(voice[v].pitch_ctr >= 0) {
|
||||||
|
voice[v].pitch_ctr -= 0x1000;
|
||||||
|
|
||||||
|
voice[v].brr_data_index++;
|
||||||
|
voice[v].brr_data_index &= 3;
|
||||||
|
|
||||||
|
if(voice[v].brr_index == 0) {
|
||||||
|
voice[v].brr_header = readb(voice[v].brr_ptr);
|
||||||
|
|
||||||
|
if(voice[v].brr_header_flags() == BRR_END) {
|
||||||
|
status.ENDX |= (1 << v);
|
||||||
|
voice[v].env_state = SILENCE;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
|
||||||
|
if(voice[v].env_state != SILENCE) {
|
||||||
|
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||||
|
if(voice[v].brr_index & 1) {
|
||||||
|
sample = sclip<4>(sample);
|
||||||
|
} else {
|
||||||
|
sample = sclip<4>(sample >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(voice[v].brr_header_shift() <= 12) {
|
||||||
|
sample = (sample << voice[v].brr_header_shift() >> 1);
|
||||||
|
} else {
|
||||||
|
sample &= ~0x7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(voice[v].brr_header_filter()) {
|
||||||
|
case 0: //direct
|
||||||
|
break;
|
||||||
|
case 1: //15/16
|
||||||
|
sample += S(-1) + ((-S(-1)) >> 4);
|
||||||
|
break;
|
||||||
|
case 2: //61/32 - 15/16
|
||||||
|
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
|
||||||
|
- S(-2) + (S(-2) >> 4);
|
||||||
|
break;
|
||||||
|
case 3: //115/64 - 13/16
|
||||||
|
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
|
||||||
|
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
S(0) = sample = sclip<15>(sclamp<16>(sample));
|
||||||
|
} else {
|
||||||
|
S(0) = sample = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(++voice[v].brr_index > 15) {
|
||||||
|
voice[v].brr_index = 0;
|
||||||
|
if(voice[v].brr_header_flags() & BRR_END) {
|
||||||
|
if(voice[v].brr_header_flags() & BRR_LOOP) {
|
||||||
|
status.ENDX |= (1 << v);
|
||||||
|
}
|
||||||
|
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||||
|
voice[v].brr_looped = true;
|
||||||
|
} else {
|
||||||
|
voice[v].brr_ptr += 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* volume envelope adjust
|
||||||
|
*****/
|
||||||
|
voice[v].env_ctr += voice[v].env_rate;
|
||||||
|
|
||||||
|
if(voice[v].env_ctr >= 0x7800) {
|
||||||
|
voice[v].env_ctr -= 0x7800;
|
||||||
|
switch(voice[v].env_mode) {
|
||||||
|
case DIRECT:
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
break;
|
||||||
|
case LINEAR_DEC:
|
||||||
|
voice[v].envx -= 32;
|
||||||
|
if(voice[v].envx <= 0) {
|
||||||
|
voice[v].envx = 0;
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
voice[v].env_mode = DIRECT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LINEAR_INC:
|
||||||
|
voice[v].envx += 32;
|
||||||
|
if(voice[v].envx >= 0x7ff) {
|
||||||
|
voice[v].envx = 0x7ff;
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
voice[v].env_mode = DIRECT;
|
||||||
|
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
|
||||||
|
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXP_DEC:
|
||||||
|
//multiply by 255/256ths
|
||||||
|
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
|
||||||
|
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
|
||||||
|
voice[v].env_state = SUSTAIN;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
} else if(voice[v].envx <= 0) {
|
||||||
|
voice[v].envx = 0;
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
voice[v].env_mode = DIRECT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BENT_INC:
|
||||||
|
if(voice[v].envx < 0x600) {
|
||||||
|
voice[v].envx += 32;
|
||||||
|
} else {
|
||||||
|
voice[v].envx += 8;
|
||||||
|
|
||||||
|
if(voice[v].envx >= 0x7ff) {
|
||||||
|
voice[v].envx = 0x7ff;
|
||||||
|
voice[v].env_rate = 0;
|
||||||
|
voice[v].env_mode = DIRECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FAST_ATTACK:
|
||||||
|
voice[v].envx += 0x400;
|
||||||
|
if(voice[v].envx >= 0x7ff) {
|
||||||
|
voice[v].envx = 0x7ff;
|
||||||
|
|
||||||
|
//attack raises to max envx. if sustain is also set to max envx, skip decay phase
|
||||||
|
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RELEASE_DEC:
|
||||||
|
voice[v].envx -= 8;
|
||||||
|
if(voice[v].envx <= 0) {
|
||||||
|
voice[v].env_state = SILENCE;
|
||||||
|
voice[v].AdjustEnvelope();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
voice[v].ENVX = voice[v].envx >> 4;
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* gaussian interpolation / noise
|
||||||
|
*****/
|
||||||
|
if(status.NON & (1 << v)) {
|
||||||
|
sample = sclip<15>(status.noise_sample);
|
||||||
|
} else {
|
||||||
|
int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||||
|
sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11);
|
||||||
|
sample += ((gaussian_table[255 - d] * S(-2)) >> 11);
|
||||||
|
sample += ((gaussian_table[512 + d] * S(-1)) >> 11);
|
||||||
|
sample = sclip <15>(sample);
|
||||||
|
sample += ((gaussian_table[256 + d] * S( 0)) >> 11);
|
||||||
|
sample = sclamp<15>(sample);
|
||||||
|
}
|
||||||
|
#undef S
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* envelope / volume adjust
|
||||||
|
*****/
|
||||||
|
sample = (sample * voice[v].envx) >> 11;
|
||||||
|
voice[v].outx = sample << 1;
|
||||||
|
voice[v].OUTX = sample >> 7;
|
||||||
|
|
||||||
|
if(!status.mute()) {
|
||||||
|
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||||
|
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((status.EON & (1 << v)) && status.echo_write()) {
|
||||||
|
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||||
|
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* echo (FIR) adjust
|
||||||
|
*****/
|
||||||
|
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7]
|
||||||
|
status.fir_buffer_index++;
|
||||||
|
F(0,0) = readw((status.esa << 8) + status.echo_index + 0);
|
||||||
|
F(1,0) = readw((status.esa << 8) + status.echo_index + 2);
|
||||||
|
|
||||||
|
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||||
|
F(0,-1) * status.FIR[6] +
|
||||||
|
F(0,-2) * status.FIR[5] +
|
||||||
|
F(0,-3) * status.FIR[4] +
|
||||||
|
F(0,-4) * status.FIR[3] +
|
||||||
|
F(0,-5) * status.FIR[2] +
|
||||||
|
F(0,-6) * status.FIR[1] +
|
||||||
|
F(0,-7) * status.FIR[0]);
|
||||||
|
|
||||||
|
fir_sampler = (F(1,-0) * status.FIR[7] +
|
||||||
|
F(1,-1) * status.FIR[6] +
|
||||||
|
F(1,-2) * status.FIR[5] +
|
||||||
|
F(1,-3) * status.FIR[4] +
|
||||||
|
F(1,-4) * status.FIR[3] +
|
||||||
|
F(1,-5) * status.FIR[2] +
|
||||||
|
F(1,-6) * status.FIR[1] +
|
||||||
|
F(1,-7) * status.FIR[0]);
|
||||||
|
#undef F
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* update echo buffer
|
||||||
|
*****/
|
||||||
|
if(status.echo_write()) {
|
||||||
|
esamplel += (fir_samplel * status.EFB) >> 14;
|
||||||
|
esampler += (fir_sampler * status.EFB) >> 14;
|
||||||
|
|
||||||
|
esamplel = sclamp<16>(esamplel);
|
||||||
|
esampler = sclamp<16>(esampler);
|
||||||
|
|
||||||
|
writew((status.esa << 8) + status.echo_index + 0, esamplel);
|
||||||
|
writew((status.esa << 8) + status.echo_index + 2, esampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
status.echo_index += 4;
|
||||||
|
if(status.echo_index >= status.echo_length) {
|
||||||
|
status.echo_index = 0;
|
||||||
|
status.echo_length = (status.EDL & 0x0f) << 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ESA read occurs at roughly 22/32th sample
|
||||||
|
//ESA fetch occurs at roughly 29/32th sample
|
||||||
|
//as this is not a subsample-level S-DSP emulator,
|
||||||
|
//simulate ~25/32th delay by caching ESA for one
|
||||||
|
//complete sample ...
|
||||||
|
status.esa = status.ESA;
|
||||||
|
|
||||||
|
/*****
|
||||||
|
* main output adjust
|
||||||
|
*****/
|
||||||
|
if(!status.mute()) {
|
||||||
|
msamplel = (msamplel * status.MVOLL) >> 7;
|
||||||
|
msampler = (msampler * status.MVOLR) >> 7;
|
||||||
|
|
||||||
|
msamplel += (fir_samplel * status.EVOLL) >> 14;
|
||||||
|
msampler += (fir_sampler * status.EVOLR) >> 14;
|
||||||
|
|
||||||
|
msamplel = sclamp<16>(msamplel);
|
||||||
|
msampler = sclamp<16>(msampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
snes.audio.update(msamplel, msampler);
|
||||||
|
scheduler.addclocks_dsp(32 * 3 * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
aDSP::aDSP() {}
|
||||||
|
aDSP::~aDSP() {}
|
||||||
172
bsnes/dsp/adsp/adsp.hpp
Executable file
172
bsnes/dsp/adsp/adsp.hpp
Executable file
@ -0,0 +1,172 @@
|
|||||||
|
class aDSP : public DSP {
|
||||||
|
private:
|
||||||
|
uint8 dspram[128];
|
||||||
|
uint8 *spcram;
|
||||||
|
|
||||||
|
uint32 dsp_counter;
|
||||||
|
|
||||||
|
enum { BRR_END = 1, BRR_LOOP = 2 };
|
||||||
|
|
||||||
|
uint8 readb (uint16 addr);
|
||||||
|
uint16 readw (uint16 addr);
|
||||||
|
void writeb(uint16 addr, uint8 data);
|
||||||
|
void writew(uint16 addr, uint16 data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const uint16 rate_table[32];
|
||||||
|
static const int16 gaussian_table[512];
|
||||||
|
|
||||||
|
enum EnvelopeStates {
|
||||||
|
ATTACK,
|
||||||
|
DECAY,
|
||||||
|
SUSTAIN,
|
||||||
|
RELEASE,
|
||||||
|
SILENCE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EnvelopeModes {
|
||||||
|
DIRECT,
|
||||||
|
LINEAR_DEC,
|
||||||
|
EXP_DEC,
|
||||||
|
LINEAR_INC,
|
||||||
|
BENT_INC,
|
||||||
|
|
||||||
|
FAST_ATTACK,
|
||||||
|
RELEASE_DEC
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Status {
|
||||||
|
//$0c,$1c
|
||||||
|
int8 MVOLL, MVOLR;
|
||||||
|
//$2c,$3c
|
||||||
|
int8 EVOLL, EVOLR;
|
||||||
|
//$4c,$5c
|
||||||
|
uint8 KON, KOFF;
|
||||||
|
//$6c
|
||||||
|
uint8 FLG;
|
||||||
|
//$7c
|
||||||
|
uint8 ENDX;
|
||||||
|
//$0d
|
||||||
|
int8 EFB;
|
||||||
|
//$2d,$3d,$4d
|
||||||
|
uint8 PMON, NON, EON;
|
||||||
|
//$5d
|
||||||
|
uint8 DIR;
|
||||||
|
//$6d,$7d
|
||||||
|
uint8 ESA, EDL;
|
||||||
|
|
||||||
|
//$xf
|
||||||
|
int8 FIR[8];
|
||||||
|
|
||||||
|
//internal variables
|
||||||
|
uint8 kon, esa;
|
||||||
|
|
||||||
|
int16 noise_ctr, noise_rate;
|
||||||
|
uint16 noise_sample;
|
||||||
|
|
||||||
|
uint16 echo_index, echo_length;
|
||||||
|
int16 fir_buffer[2][8];
|
||||||
|
uint8 fir_buffer_index;
|
||||||
|
|
||||||
|
//functions
|
||||||
|
bool soft_reset() { return !!(FLG & 0x80); }
|
||||||
|
bool mute() { return !!(FLG & 0x40); }
|
||||||
|
bool echo_write() { return !(FLG & 0x20); }
|
||||||
|
} status;
|
||||||
|
|
||||||
|
struct Voice {
|
||||||
|
//$x0-$x1
|
||||||
|
int8 VOLL, VOLR;
|
||||||
|
//$x2-$x3
|
||||||
|
int16 PITCH;
|
||||||
|
//$x4
|
||||||
|
uint8 SRCN;
|
||||||
|
//$x5-$x7
|
||||||
|
uint8 ADSR1, ADSR2, GAIN;
|
||||||
|
//$x8-$x9
|
||||||
|
uint8 ENVX, OUTX;
|
||||||
|
|
||||||
|
//internal variables
|
||||||
|
int16 pitch_ctr;
|
||||||
|
|
||||||
|
int8 brr_index;
|
||||||
|
uint16 brr_ptr;
|
||||||
|
uint8 brr_header;
|
||||||
|
bool brr_looped;
|
||||||
|
|
||||||
|
int16 brr_data[4];
|
||||||
|
uint8 brr_data_index;
|
||||||
|
|
||||||
|
int16 envx;
|
||||||
|
uint16 env_ctr, env_rate, env_sustain;
|
||||||
|
enum EnvelopeStates env_state;
|
||||||
|
enum EnvelopeModes env_mode;
|
||||||
|
|
||||||
|
int16 outx;
|
||||||
|
|
||||||
|
//functions
|
||||||
|
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||||
|
|
||||||
|
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||||
|
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||||
|
uint8 brr_header_flags() { return brr_header & 3; }
|
||||||
|
|
||||||
|
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
|
||||||
|
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||||
|
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||||
|
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||||
|
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||||
|
|
||||||
|
void AdjustEnvelope() {
|
||||||
|
if(env_state == SILENCE) {
|
||||||
|
env_mode = DIRECT;
|
||||||
|
env_rate = 0;
|
||||||
|
envx = 0;
|
||||||
|
} else if(env_state == RELEASE) {
|
||||||
|
env_mode = RELEASE_DEC;
|
||||||
|
env_rate = 0x7800;
|
||||||
|
} else if(ADSR_enabled()) {
|
||||||
|
switch(env_state) {
|
||||||
|
case ATTACK:
|
||||||
|
env_rate = rate_table[(ADSR_attack() << 1) + 1];
|
||||||
|
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||||
|
break;
|
||||||
|
case DECAY:
|
||||||
|
env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
|
||||||
|
env_mode = EXP_DEC;
|
||||||
|
break;
|
||||||
|
case SUSTAIN:
|
||||||
|
env_rate = rate_table[ADSR_sus_rate()];
|
||||||
|
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(GAIN & 0x80) {
|
||||||
|
switch(GAIN & 0x60) {
|
||||||
|
case 0x00: env_mode = LINEAR_DEC; break;
|
||||||
|
case 0x20: env_mode = EXP_DEC; break;
|
||||||
|
case 0x40: env_mode = LINEAR_INC; break;
|
||||||
|
case 0x60: env_mode = BENT_INC; break;
|
||||||
|
}
|
||||||
|
env_rate = rate_table[GAIN & 0x1f];
|
||||||
|
} else {
|
||||||
|
env_mode = DIRECT;
|
||||||
|
env_rate = 0;
|
||||||
|
envx = (GAIN & 0x7f) << 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} voice[8];
|
||||||
|
|
||||||
|
public:
|
||||||
|
void enter();
|
||||||
|
void run();
|
||||||
|
|
||||||
|
uint8 read (uint8 addr);
|
||||||
|
void write(uint8 addr, uint8 data);
|
||||||
|
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
aDSP();
|
||||||
|
~aDSP();
|
||||||
|
};
|
||||||
77
bsnes/dsp/adsp/adsp_tables.cpp
Executable file
77
bsnes/dsp/adsp/adsp_tables.cpp
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#ifdef ADSP_CPP
|
||||||
|
|
||||||
|
const uint16 aDSP::rate_table[32] = {
|
||||||
|
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
|
||||||
|
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
|
||||||
|
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
|
||||||
|
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 aDSP::gaussian_table[512] = {
|
||||||
|
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||||
|
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||||
|
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
||||||
|
0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
|
||||||
|
0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004,
|
||||||
|
0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
|
||||||
|
0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008,
|
||||||
|
0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
|
||||||
|
0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E,
|
||||||
|
0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
|
||||||
|
0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
|
||||||
|
0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
|
||||||
|
0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021,
|
||||||
|
0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
|
||||||
|
0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030,
|
||||||
|
0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
|
||||||
|
0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042,
|
||||||
|
0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
|
||||||
|
0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059,
|
||||||
|
0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
|
||||||
|
0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075,
|
||||||
|
0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
|
||||||
|
0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096,
|
||||||
|
0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
|
||||||
|
0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC,
|
||||||
|
0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
|
||||||
|
0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9,
|
||||||
|
0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
|
||||||
|
0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B,
|
||||||
|
0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
|
||||||
|
0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153,
|
||||||
|
0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
|
||||||
|
0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191,
|
||||||
|
0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
|
||||||
|
0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5,
|
||||||
|
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
|
||||||
|
0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C,
|
||||||
|
0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
|
||||||
|
0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267,
|
||||||
|
0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
|
||||||
|
0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5,
|
||||||
|
0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
|
||||||
|
0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304,
|
||||||
|
0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
|
||||||
|
0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353,
|
||||||
|
0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
|
||||||
|
0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F,
|
||||||
|
0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
|
||||||
|
0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9,
|
||||||
|
0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
|
||||||
|
0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E,
|
||||||
|
0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
|
||||||
|
0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C,
|
||||||
|
0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
|
||||||
|
0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2,
|
||||||
|
0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
|
||||||
|
0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0,
|
||||||
|
0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
|
||||||
|
0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3,
|
||||||
|
0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
|
||||||
|
0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B,
|
||||||
|
0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
|
||||||
|
0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517,
|
||||||
|
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //ifdef ADSP_CPP
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user