Update to bsnes v047 release.

The most notable feature for this release is the addition of SuperFX support. This enables an additional eight commercial games, and two unreleased betas, to run with full support. Most notably of these would be Super Mario World 2: Yoshi's Island and Starfox. Though timing is not quite perfect just yet, there should be no known issues with any titles at the time of this release. That means there should only be two official, commercially-released titles that are not compatible with bsnes at this time: Quick-move Shogi Match with Nidan Rank-holder Morita 1 and 2 (using the ST011 and ST018 co-processors, respectively.)
SuperFX support was the work of many people. GIGO was a great help by providing the source code to his SuperFX emulator (for reference; the implementation in bsnes is my own design), _Demo_ was very helpful in getting Starfox to work properly, and Jonas Quinn provided roughly a half-dozen very important bug fixes that affected nearly every SuperFX game. Without them, this release would not be possible. So please do thank them if you appreciate SuperFX support in bsnes.
Please note that SuperFX emulation is very demanding. I hate to have to repeat this, but once again: bsnes is a reference emulator. It exists to better understand the SNES hardware. It is written in such a manner as to be friendly to other developers (both emulator authors and game programmers), and the findings are meant to help improve other emulators. As far as I know, bsnes is the first emulator to fully support all SuperFX caching mechanisms (instruction cache, both pixel caches, ROM and RAM buffering caches, ...); as well as many other obscure features, such as full support for ROM / RAM access toggling between the SNES and SuperFX CPUs, and multiplier overhead timing. By emulating these, I was able to discover what additional components are needed to emulate Dirt Racer and Power Slide, two titles that no emulator has yet been able to run (they aren't very good games, you weren't missing much.) It should be possible to backport these fixes to faster emulators now.
That said, with a Core 2 Duo E8400 @ 3GHz, on average I get ~100fps in Super Mario World 2, ~95fps in Starfox and ~85fps in Doom. Compare this to ~165fps in Zelda 3, a game that does not use the SuperFX chip. My binary releases also target 32-bit x86 architecture. For those capable of building 64-bit binaries, especially Linux users, that should provide an additional ~10% speedup. Be sure to profile the application if you build it yourself.
Lastly on the SuperFX front, note that Starfox 2 is fully playable, but that most images floating around have corrupted headers. I do not attempt to repair bad headers, so these images will not work. Please either use NSRT on the Japanese version, or use Gideon Zhi's English fan translation patch, if you are having trouble running this title.
With that out the way, a few other improvements have been made to this release: xinput1_3.dll is no longer required for the Windows port (though you will need it if you want to use an Xbox 360 controller), the video drivers in ruby now allocate the smallest texture size possible for blitting video, and the code has been updated with preliminary compilation support for Mac OS X. Note that I will not be releasing binaries for this: it is primarily meant for developers and for porting my other libraries to the platform. Richard Bannister maintains a much better OS X port with full EE support and a native Apple GUI that follows their interface guidelines much better than a Qt port ever could. He has also synced the Mac port with this release. You can find a link to that in the bsnes download section.
This commit is contained in:
byuu 2009-06-07 11:57:05 +00:00
parent f8e425ff49
commit 7b0e484c18
285 changed files with 30554 additions and 28393 deletions

View File

@ -1,4 +1,5 @@
include lib/nall/Makefile include lib/nall/Makefile
include lib/nall/Makefile-qt
ui = ui_qt ui = ui_qt
################ ################
@ -8,7 +9,7 @@ ui = ui_qt
c := $(compiler) c := $(compiler)
cpp := $(subst cc,++,$(compiler)) cpp := $(subst cc,++,$(compiler))
flags := -O3 -fomit-frame-pointer -Ilib flags := -O3 -fomit-frame-pointer -Ilib
link := -s link :=
# profile-guided instrumentation: # profile-guided instrumentation:
# flags += -fprofile-generate # flags += -fprofile-generate
@ -22,19 +23,31 @@ link := -s
################ ################
ifeq ($(platform),x) ifeq ($(platform),x)
ruby := video.glx video.xv video.sdl link += -s
ruby := video.glx video.xv video.sdl video.qtimage
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += input.sdl input.x ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
ruby := video.qtimage
ruby += audio.openal
ruby += input.carbon
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win) else ifeq ($(platform),win)
ruby := video.direct3d video.wgl video.directdraw video.gdi link += -mwindows
# link += -mconsole
link += -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
ruby := video.direct3d video.wgl video.directdraw video.gdi video.qtimage
ruby += audio.directsound ruby += audio.directsound
ruby += input.rawinput input.directinput ruby += input.rawinput input.directinput
link += -mwindows link += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
# link += -mconsole
link += -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-s -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else else
unknown_platform: help; unknown_platform: help;
endif endif
@ -43,7 +56,8 @@ endif
### ruby ### ### ruby ###
############ ############
rubyflags = $(call ifhas,.sdl,$(ruby),`sdl-config --cflags`) rubyflags := $(call ifhas,.sdl,$(ruby),`sdl-config --cflags`)
rubyflags += $(call ifhas,.qt,$(ruby),$(qtinc))
link += $(call ifhas,.sdl,$(ruby),`sdl-config --libs`) link += $(call ifhas,.sdl,$(ruby),`sdl-config --libs`)
link += $(call ifhas,video.direct3d,$(ruby),-ld3d9) link += $(call ifhas,video.direct3d,$(ruby),-ld3d9)
@ -54,19 +68,18 @@ link += $(call ifhas,video.xv,$(ruby),-lXv)
link += $(call ifhas,audio.alsa,$(ruby),-lasound) link += $(call ifhas,audio.alsa,$(ruby),-lasound)
link += $(call ifhas,audio.ao,$(ruby),-lao) link += $(call ifhas,audio.ao,$(ruby),-lao)
link += $(call ifhas,audio.directsound,$(ruby),-ldsound) link += $(call ifhas,audio.directsound,$(ruby),-ldsound)
link += $(call ifhas,audio.openal,$(ruby),$(if $(call streq,$(platform),x),-lopenal,-lopenal32))
link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple) link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple)
link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid) link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid)
link += $(call ifhas,input.rawinput,$(ruby),-lxinput -ldinput8 -ldxguid) link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
#################### ####################
### core objects ### ### core objects ###
#################### ####################
objects = libco ruby libreader libfilter string \ objects := libco ruby libreader libfilter
system cartridge cheat \ objects += system cartridge cheat
memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu \ objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
sgb sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 objects += sgb superfx sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
ifeq ($(enable_gzip),true) ifeq ($(enable_gzip),true)
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
@ -110,7 +123,6 @@ obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@ $(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/* obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/*
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/* obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
obj/string.o: lib/nall/string.cpp lib/nall/*
################# #################
### utilities ### ### utilities ###
@ -167,6 +179,7 @@ obj/system.o: system/system.cpp $(call rwildcard,system/)
##################### #####################
obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/) obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/)
obj/superfx.o: chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/) obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/* obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/* obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
@ -216,7 +229,12 @@ obj/winout.o : lib/libjma/winout.cpp lib/libjma/*
############### ###############
build: ui_build $(objects) build: ui_build $(objects)
$(strip $(cpp) -o../bsnes $(objects) $(link)) ifeq ($(platform),osx)
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
else
$(strip $(cpp) -o ../bsnes $(objects) $(link))
endif
install: install:
install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes
@ -250,4 +268,3 @@ help:
@echo "" @echo ""
@echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true" @echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true"
@echo "" @echo ""

View File

@ -1,4 +1,4 @@
#define BSNES_VERSION "0.046" #define BSNES_VERSION "0.047"
#define BSNES_TITLE "bsnes v" BSNES_VERSION #define BSNES_TITLE "bsnes v" BSNES_VERSION
#define BUSCORE sBus #define BUSCORE sBus
@ -41,4 +41,3 @@ typedef uint16_t uint16;
typedef uint32_t uint32; typedef uint32_t uint32;
#include "interface.hpp" #include "interface.hpp"

View File

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

View File

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

View File

@ -22,11 +22,8 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
const uint8 company = data[index + Company]; const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f; const uint8 region = data[index + CartRegion] & 0x7f;
if(data[index + RamSize] & 7) { info.ram_size = 1024 << (data[index + RamSize] & 7);
info.ram_size = 1024 << (data[index + RamSize] & 7); if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
} else {
info.ram_size = 0;
}
//0, 1, 13 = NTSC; 2 - 12 = PAL //0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL; info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
@ -119,6 +116,9 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true; info.superfx = true;
info.mapper = SuperFXROM;
info.ram_size = 1024 << (data[index - 3] & 7);
if(info.ram_size == 1024) info.ram_size = 0;
} }
if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {

View File

@ -1,3 +1,5 @@
@mingw32-make @mingw32-make
::@mingw32-make enable_gzip=true enable_jma=true
::@mingw32-make enable_gzip=true enable_jma=true
@pause @pause

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@ -3,38 +3,38 @@
#define DSP3_CPP #define DSP3_CPP
namespace SNES { namespace SNES {
DSP3 dsp3; DSP3 dsp3;
namespace DSP3i { namespace DSP3i {
#define bool8 uint8 #define bool8 uint8
#include "dsp3emu.c" #include "dsp3emu.c"
#undef bool8 #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();
}
}; };
void DSP3::init() {
}
void DSP3::enable() {
}
void DSP3::power() {
reset();
}
void DSP3::reset() {
DSP3i::DSP3_Reset();
}
uint8 DSP3::read(unsigned addr) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::DSP3GetByte();
return DSP3i::dsp3_byte;
}
void DSP3::write(unsigned addr, uint8 data) {
DSP3i::dsp3_address = addr & 0xffff;
DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte();
}
};

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -3,21 +3,16 @@
SA1Bus sa1bus; SA1Bus sa1bus;
namespace memory { namespace memory {
VectorSelectionPage vectorsp; static VectorSelectionPage vectorsp;
StaticRAM iram(2048); static StaticRAM iram(2048);
MappedRAM &bwram = memory::cartram; static MappedRAM &bwram = memory::cartram;
CC1BWRAM cc1bwram; static CC1BWRAM cc1bwram;
BitmapRAM bitmapram; static BitmapRAM bitmapram;
} }
void SA1Bus::init() { void SA1Bus::init() {
for(uint32_t i = 0x0000; i <= 0xffff; i++) { map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(i << 8, memory::memory_unmapped, 0); for(uint16_t i = 0x2200; i <= 0x23ff; i++) memory::mmio.map(i, sa1);
}
for(uint16_t i = 0x2200; i <= 0x23ff; i++) {
memory::mmio.map(i, sa1);
}
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram); map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio); map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
@ -120,7 +115,7 @@ uint8_t BitmapRAM::read(unsigned addr) {
//4bpp //4bpp
unsigned shift = addr & 1; unsigned shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1); addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 15; case 0: return (memory::cartram.read(addr) >> 0) & 15;
case 1: return (memory::cartram.read(addr) >> 4) & 15; case 1: return (memory::cartram.read(addr) >> 4) & 15;
} }
@ -128,7 +123,7 @@ uint8_t BitmapRAM::read(unsigned addr) {
//2bpp //2bpp
unsigned shift = addr & 3; unsigned shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1); addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 3; case 0: return (memory::cartram.read(addr) >> 0) & 3;
case 1: return (memory::cartram.read(addr) >> 2) & 3; case 1: return (memory::cartram.read(addr) >> 2) & 3;
case 2: return (memory::cartram.read(addr) >> 4) & 3; case 2: return (memory::cartram.read(addr) >> 4) & 3;
@ -142,7 +137,7 @@ void BitmapRAM::write(unsigned addr, uint8_t data) {
//4bpp //4bpp
uint8_t shift = addr & 1; uint8_t shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1); addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break; case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break; case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
} }
@ -150,7 +145,7 @@ void BitmapRAM::write(unsigned addr, uint8_t data) {
//2bpp //2bpp
uint8_t shift = addr & 3; uint8_t shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1); addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break; case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break; case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break; case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;

View File

@ -21,11 +21,3 @@ struct BitmapRAM : Memory {
alwaysinline uint8_t read(unsigned); alwaysinline uint8_t read(unsigned);
alwaysinline void write(unsigned, uint8_t); alwaysinline void write(unsigned, uint8_t);
}; };
namespace memory {
extern VectorSelectionPage vectorsp;
extern StaticRAM iram;
extern MappedRAM &bwram;
extern CC1BWRAM cc1bwram;
extern BitmapRAM bitmapram;
}

View File

@ -315,4 +315,3 @@ SA1::SA1() {
} }
}; };

View File

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

View File

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

View File

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

View File

@ -1,162 +1,162 @@
/************************************************************************ /************************************************************************
S-DD1'algorithm emulation code S-DD1'algorithm emulation code
------------------------------ ------------------------------
Author: Andreas Naive Author: Andreas Naive
Date: August 2003 Date: August 2003
Last update: October 2004 Last update: October 2004
This code is Public Domain. There is no copyright holded by the author. 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 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 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. possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied. This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it. No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and 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 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, 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 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 indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past. S-DD1 issue in the past.
An algorithm's documentation is available as a separate document. An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is The implementation is obvious when the algorithm is
understood. understood.
************************************************************************/ ************************************************************************/
typedef uint8_t bool8; typedef uint8_t bool8;
class SDD1_IM { //Input Manager class SDD1_IM { //Input Manager
public: public:
SDD1_IM(void) {} SDD1_IM(void) {}
void prepareDecomp(uint32 in_buf); void prepareDecomp(uint32 in_buf);
uint8 getCodeword(const uint8 code_len); uint8 getCodeword(const uint8 code_len);
private: private:
uint32 byte_ptr; uint32 byte_ptr;
uint8 bit_count; uint8 bit_count;
}; };
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
class SDD1_GCD { //Golomb-Code Decoder class SDD1_GCD { //Golomb-Code Decoder
public: public:
SDD1_GCD(SDD1_IM *associatedIM); SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind); void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
private: private:
SDD1_IM *const IM; SDD1_IM *const IM;
}; };
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
class SDD1_BG { // Bits Generator class SDD1_BG { // Bits Generator
public: public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code); SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
void prepareDecomp(void); void prepareDecomp(void);
uint8 getBit(bool8 *endOfRun); uint8 getBit(bool8 *endOfRun);
private: private:
const uint8 code_num; const uint8 code_num;
uint8 MPScount; uint8 MPScount;
bool8 LPSind; bool8 LPSind;
SDD1_GCD *const GCD; SDD1_GCD *const GCD;
}; };
//////////////////////////////////////////////// ////////////////////////////////////////////////
class SDD1_PEM { //Probability Estimation Module class SDD1_PEM { //Probability Estimation Module
public: public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1, SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3, SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5, SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7); SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void); void prepareDecomp(void);
uint8 getBit(uint8 context); uint8 getBit(uint8 context);
private: private:
struct state { struct state {
uint8 code_num; uint8 code_num;
uint8 nextIfMPS; uint8 nextIfMPS;
uint8 nextIfLPS; uint8 nextIfLPS;
}; };
static const state evolution_table[]; static const state evolution_table[];
struct SDD1_ContextInfo { struct SDD1_ContextInfo {
uint8 status; uint8 status;
uint8 MPS; uint8 MPS;
} contextInfo[32]; } contextInfo[32];
SDD1_BG * BG[8]; SDD1_BG * BG[8];
}; };
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
class SDD1_CM { //Context Model class SDD1_CM { //Context Model
public: public:
SDD1_CM(SDD1_PEM *associatedPEM); SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint32 first_byte); void prepareDecomp(uint32 first_byte);
uint8 getBit(void); uint8 getBit(void);
private: private:
uint8 bitplanesInfo; uint8 bitplanesInfo;
uint8 contextBitsInfo; uint8 contextBitsInfo;
uint8 bit_number; uint8 bit_number;
uint8 currBitplane; uint8 currBitplane;
uint16 prevBitplaneBits[8]; uint16 prevBitplaneBits[8];
SDD1_PEM *const PEM; SDD1_PEM *const PEM;
}; };
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
class SDD1_OL { //Output Logic class SDD1_OL { //Output Logic
public: public:
SDD1_OL(SDD1_CM *associatedCM); SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf); void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
void launch(void); void launch(void);
private: private:
uint8 bitplanesInfo; uint8 bitplanesInfo;
uint16 length; uint16 length;
uint8 *buffer; uint8 *buffer;
SDD1_CM *const CM; SDD1_CM *const CM;
}; };
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////
class SDD1emu { class SDD1emu {
public: public:
SDD1emu(void); SDD1emu(void);
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf); void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
private: private:
SDD1_IM IM; SDD1_IM IM;
SDD1_GCD GCD; SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3; 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_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM; SDD1_PEM PEM;
SDD1_CM CM; SDD1_CM CM;
SDD1_OL OL; SDD1_OL OL;
}; };

View File

@ -63,4 +63,3 @@ void SuperGameBoy::reset() {
} }
}; };

View File

@ -25,4 +25,3 @@ private:
}; };
extern SuperGameBoy sgb; extern SuperGameBoy sgb;

View File

@ -674,4 +674,3 @@ SPC7110::SPC7110() {
} }
}; };

View File

@ -229,4 +229,3 @@ SRTC::SRTC() {
} }
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,4 +48,3 @@ CPUcore::CPUcore() {
} }
}; };

View File

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

View File

@ -138,4 +138,3 @@ void CPUcore::update_table() {
} }
#endif #endif

View File

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

View File

@ -2,18 +2,18 @@
#define CPU_CPP #define CPU_CPP
namespace SNES { namespace SNES {
void CPU::power() {
cpu_version = config.cpu.version;
}
void CPU::reset() {
}
CPU::CPU() {
}
CPU::~CPU() {
}
};
void CPU::power() {
cpu_version = config.cpu.version;
}
void CPU::reset() {
}
CPU::CPU() {
}
CPU::~CPU() {
}
};

View File

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

View File

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

View File

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

View File

@ -2,29 +2,26 @@
void sCPU::op_io() { void sCPU::op_io() {
status.clock_count = 6; status.clock_count = 6;
precycle_edge();
add_clocks(6);
cycle_edge(); cycle_edge();
add_clocks(6);
} }
uint8 sCPU::op_read(uint32 addr) { uint8 sCPU::op_read(uint32 addr) {
status.clock_count = speed(addr); status.clock_count = speed(addr);
precycle_edge(); cycle_edge();
add_clocks(status.clock_count - 4); add_clocks(status.clock_count - 4);
scheduler.sync_cpucop(); scheduler.sync_cpucop();
regs.mdr = bus.read(addr); regs.mdr = bus.read(addr);
add_clocks(4); add_clocks(4);
cycle_edge();
return regs.mdr; return regs.mdr;
} }
void sCPU::op_write(uint32 addr, uint8 data) { void sCPU::op_write(uint32 addr, uint8 data) {
status.clock_count = speed(addr); status.clock_count = speed(addr);
precycle_edge(); cycle_edge();
add_clocks(status.clock_count); add_clocks(status.clock_count);
scheduler.sync_cpucop(); scheduler.sync_cpucop();
bus.write(addr, regs.mdr = data); bus.write(addr, regs.mdr = data);
cycle_edge();
} }
unsigned sCPU::speed(unsigned addr) const { unsigned sCPU::speed(unsigned addr) const {
@ -38,4 +35,3 @@ unsigned sCPU::speed(unsigned addr) const {
} }
#endif #endif

View File

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

View File

@ -534,4 +534,4 @@ void sCPU::mmio_write(unsigned addr, uint8 data) {
} }
} }
#endif //ifdef SCPU_CPP #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,14 +52,6 @@ void sCPU::scanline() {
} }
} }
//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. //used to test for H/DMA, which can trigger on the edge of every opcode cycle.
void sCPU::cycle_edge() { void sCPU::cycle_edge() {
while(cycle_edge_state) { while(cycle_edge_state) {
@ -91,30 +83,34 @@ void sCPU::cycle_edge() {
//.. Run one bus CPU cycle //.. Run one bus CPU cycle
//.. CPU sync //.. CPU sync
if(status.dma_state == DmaRun) { if(status.dma_active == true) {
if(status.hdma_pending) { if(status.hdma_pending) {
status.hdma_pending = false; status.hdma_pending = false;
if(hdma_enabled_channels()) { if(hdma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync dma_add_clocks(8 - dma_counter());
status.hdma_mode == 0 ? hdma_init() : hdma_run(); status.hdma_mode == 0 ? hdma_init() : hdma_run();
if(!dma_enabled_channels()) status.dma_state = DmaCpuSync; if(!dma_enabled_channels()) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
} }
} }
if(status.dma_pending) { if(status.dma_pending) {
status.dma_pending = false; status.dma_pending = false;
if(dma_enabled_channels()) { if(dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync dma_add_clocks(8 - dma_counter());
dma_run(); dma_run();
status.dma_state = DmaCpuSync; add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
} }
} }
} }
if(status.dma_state == DmaInactive) { if(status.dma_active == false) {
if(status.dma_pending || status.hdma_pending) { if(status.dma_pending || status.hdma_pending) {
status.dma_clocks = 0; status.dma_clocks = 0;
status.dma_state = DmaRun; status.dma_active = true;
} }
} }
} }
@ -159,12 +155,12 @@ void sCPU::timing_reset() {
status.irq_pending = false; status.irq_pending = false;
status.irq_hold = false; status.irq_hold = false;
status.dma_active = false;
status.dma_counter = 0; status.dma_counter = 0;
status.dma_clocks = 0; status.dma_clocks = 0;
status.dma_pending = false; status.dma_pending = false;
status.hdma_pending = false; status.hdma_pending = false;
status.hdma_mode = 0; status.hdma_mode = 0;
status.dma_state = DmaInactive;
cycle_edge_state = 0; cycle_edge_state = 0;
} }

View File

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

View File

@ -5,15 +5,19 @@
<h1>bsnes&trade; Usage Documentation</h1><br> <h1>bsnes&trade; Usage Documentation</h1><br>
bsnes is a Super Nintendo / Super Famicom emulator that strives to provide bsnes is a Super Nintendo / Super Famicom emulator that strives to provide the
the most faithful emulation experience possible. It focuses on accuracy and most faithful hardware emulation possible. It focuses on accuracy and clean
clean code; over speed and features. code, rather than speed and special features. It is meant as a reference
emulator to document how the underlying hardware works. It is thus very useful
for development and research. And while it can be used for general purpose
gaming, it will require significantly more powerful hardware than a typical
emulator.
<hr> <hr>
<h2><u>Modes of Operation</u></h2><br> <h2><u>Modes of Operation</u></h2><br>
bsnes is capable of running both in its default multi-user mode, as well as bsnes is capable of running both in its default multi-user mode, as well as in
in single-user mode.<br> single-user mode.<br>
<br> <br>
In multi-user mode, configuration data is stored inside the user's home In multi-user mode, configuration data is stored inside the user's home
@ -39,16 +43,15 @@ configuration data.
<h2><u>Known Limitations</u></h2><br> <h2><u>Known Limitations</u></h2><br>
<b>Cartridge co-processors:</b> certain cartridges contain special co-processor chips to enhance <b>Satellaview BS-X emulation:</b> this hardware is only partially supported.
their functionality. Some of these are either partially or completely unsupported. A message box This is mostly because the satellite network it used (St. GIGA) has been shut
warning will pop up when attempting to load such a cartridge.<br> down. Access to this network would be required to properly reverse engineer much
of the hardware. Working around this would require game-specific hacks, which
are contrary to the design goals of this emulator. As a result, most BS-X
software will not function correctly.<br>
<br> <br>
<b>Satellaview BS-X emulation:</b> this hardware is only partially supported. As a result, <b>Savestates:</b> due to the internal design of bsnes, it is not plausible to
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> implement support for savestate and/or rewind functionality.<br>
<br> <br>
@ -58,6 +61,7 @@ implement support for savestate and/or rewind functionality.<br>
<h2><u>Contributors</u></h2> <h2><u>Contributors</u></h2>
&bull; Andreas Naive<br> &bull; Andreas Naive<br>
&bull; anomie<br> &bull; anomie<br>
&bull; _Demo_<br>
&bull; Derrick Sobodash<br> &bull; Derrick Sobodash<br>
&bull; DMV27<br> &bull; DMV27<br>
&bull; FirebrandX<br> &bull; FirebrandX<br>

File diff suppressed because it is too large Load Diff

View File

@ -1,172 +1,172 @@
class aDSP : public DSP { class aDSP : public DSP {
private: private:
uint8 dspram[128]; uint8 dspram[128];
uint8 *spcram; uint8 *spcram;
uint32 dsp_counter; uint32 dsp_counter;
enum { BRR_END = 1, BRR_LOOP = 2 }; enum { BRR_END = 1, BRR_LOOP = 2 };
uint8 readb (uint16 addr); uint8 readb (uint16 addr);
uint16 readw (uint16 addr); uint16 readw (uint16 addr);
void writeb(uint16 addr, uint8 data); void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data); void writew(uint16 addr, uint16 data);
public: public:
static const uint16 rate_table[32]; static const uint16 rate_table[32];
static const int16 gaussian_table[512]; static const int16 gaussian_table[512];
enum EnvelopeStates { enum EnvelopeStates {
ATTACK, ATTACK,
DECAY, DECAY,
SUSTAIN, SUSTAIN,
RELEASE, RELEASE,
SILENCE SILENCE
}; };
enum EnvelopeModes { enum EnvelopeModes {
DIRECT, DIRECT,
LINEAR_DEC, LINEAR_DEC,
EXP_DEC, EXP_DEC,
LINEAR_INC, LINEAR_INC,
BENT_INC, BENT_INC,
FAST_ATTACK, FAST_ATTACK,
RELEASE_DEC RELEASE_DEC
}; };
private: private:
struct Status { struct Status {
//$0c,$1c //$0c,$1c
int8 MVOLL, MVOLR; int8 MVOLL, MVOLR;
//$2c,$3c //$2c,$3c
int8 EVOLL, EVOLR; int8 EVOLL, EVOLR;
//$4c,$5c //$4c,$5c
uint8 KON, KOFF; uint8 KON, KOFF;
//$6c //$6c
uint8 FLG; uint8 FLG;
//$7c //$7c
uint8 ENDX; uint8 ENDX;
//$0d //$0d
int8 EFB; int8 EFB;
//$2d,$3d,$4d //$2d,$3d,$4d
uint8 PMON, NON, EON; uint8 PMON, NON, EON;
//$5d //$5d
uint8 DIR; uint8 DIR;
//$6d,$7d //$6d,$7d
uint8 ESA, EDL; uint8 ESA, EDL;
//$xf //$xf
int8 FIR[8]; int8 FIR[8];
//internal variables //internal variables
uint8 kon, esa; uint8 kon, esa;
int16 noise_ctr, noise_rate; int16 noise_ctr, noise_rate;
uint16 noise_sample; uint16 noise_sample;
uint16 echo_index, echo_length; uint16 echo_index, echo_length;
int16 fir_buffer[2][8]; int16 fir_buffer[2][8];
uint8 fir_buffer_index; uint8 fir_buffer_index;
//functions //functions
bool soft_reset() { return !!(FLG & 0x80); } bool soft_reset() { return !!(FLG & 0x80); }
bool mute() { return !!(FLG & 0x40); } bool mute() { return !!(FLG & 0x40); }
bool echo_write() { return !(FLG & 0x20); } bool echo_write() { return !(FLG & 0x20); }
} status; } status;
struct Voice { struct Voice {
//$x0-$x1 //$x0-$x1
int8 VOLL, VOLR; int8 VOLL, VOLR;
//$x2-$x3 //$x2-$x3
int16 PITCH; int16 PITCH;
//$x4 //$x4
uint8 SRCN; uint8 SRCN;
//$x5-$x7 //$x5-$x7
uint8 ADSR1, ADSR2, GAIN; uint8 ADSR1, ADSR2, GAIN;
//$x8-$x9 //$x8-$x9
uint8 ENVX, OUTX; uint8 ENVX, OUTX;
//internal variables //internal variables
int16 pitch_ctr; int16 pitch_ctr;
int8 brr_index; int8 brr_index;
uint16 brr_ptr; uint16 brr_ptr;
uint8 brr_header; uint8 brr_header;
bool brr_looped; bool brr_looped;
int16 brr_data[4]; int16 brr_data[4];
uint8 brr_data_index; uint8 brr_data_index;
int16 envx; int16 envx;
uint16 env_ctr, env_rate, env_sustain; uint16 env_ctr, env_rate, env_sustain;
enum EnvelopeStates env_state; enum EnvelopeStates env_state;
enum EnvelopeModes env_mode; enum EnvelopeModes env_mode;
int16 outx; int16 outx;
//functions //functions
int16 pitch_rate() { return PITCH & 0x3fff; } int16 pitch_rate() { return PITCH & 0x3fff; }
uint8 brr_header_shift() { return brr_header >> 4; } uint8 brr_header_shift() { return brr_header >> 4; }
uint8 brr_header_filter() { return (brr_header >> 2) & 3; } uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
uint8 brr_header_flags() { return brr_header & 3; } uint8 brr_header_flags() { return brr_header & 3; }
bool ADSR_enabled() { return !!(ADSR1 & 0x80); } bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; } uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
uint8 ADSR_attack() { return ADSR1 & 15; } uint8 ADSR_attack() { return ADSR1 & 15; }
uint8 ADSR_sus_level() { return ADSR2 >> 5; } uint8 ADSR_sus_level() { return ADSR2 >> 5; }
uint8 ADSR_sus_rate() { return ADSR2 & 31; } uint8 ADSR_sus_rate() { return ADSR2 & 31; }
void AdjustEnvelope() { void AdjustEnvelope() {
if(env_state == SILENCE) { if(env_state == SILENCE) {
env_mode = DIRECT; env_mode = DIRECT;
env_rate = 0; env_rate = 0;
envx = 0; envx = 0;
} else if(env_state == RELEASE) { } else if(env_state == RELEASE) {
env_mode = RELEASE_DEC; env_mode = RELEASE_DEC;
env_rate = 0x7800; env_rate = 0x7800;
} else if(ADSR_enabled()) { } else if(ADSR_enabled()) {
switch(env_state) { switch(env_state) {
case ATTACK: case ATTACK:
env_rate = rate_table[(ADSR_attack() << 1) + 1]; env_rate = rate_table[(ADSR_attack() << 1) + 1];
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC; env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
break; break;
case DECAY: case DECAY:
env_rate = rate_table[(ADSR_decay() << 1) + 0x10]; env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
env_mode = EXP_DEC; env_mode = EXP_DEC;
break; break;
case SUSTAIN: case SUSTAIN:
env_rate = rate_table[ADSR_sus_rate()]; env_rate = rate_table[ADSR_sus_rate()];
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC; env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
break; break;
} }
} else if(GAIN & 0x80) { } else if(GAIN & 0x80) {
switch(GAIN & 0x60) { switch(GAIN & 0x60) {
case 0x00: env_mode = LINEAR_DEC; break; case 0x00: env_mode = LINEAR_DEC; break;
case 0x20: env_mode = EXP_DEC; break; case 0x20: env_mode = EXP_DEC; break;
case 0x40: env_mode = LINEAR_INC; break; case 0x40: env_mode = LINEAR_INC; break;
case 0x60: env_mode = BENT_INC; break; case 0x60: env_mode = BENT_INC; break;
} }
env_rate = rate_table[GAIN & 0x1f]; env_rate = rate_table[GAIN & 0x1f];
} else { } else {
env_mode = DIRECT; env_mode = DIRECT;
env_rate = 0; env_rate = 0;
envx = (GAIN & 0x7f) << 4; envx = (GAIN & 0x7f) << 4;
} }
} }
} voice[8]; } voice[8];
public: public:
void enter(); void enter();
void run(); void run();
uint8 read (uint8 addr); uint8 read (uint8 addr);
void write(uint8 addr, uint8 data); void write(uint8 addr, uint8 data);
void power(); void power();
void reset(); void reset();
aDSP(); aDSP();
~aDSP(); ~aDSP();
}; };

View File

@ -1,77 +1,77 @@
#ifdef ADSP_CPP #ifdef ADSP_CPP
const uint16 aDSP::rate_table[32] = { const uint16 aDSP::rate_table[32] = {
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 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 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

View File

@ -1,13 +1,13 @@
class DSP { class DSP {
public: public:
virtual void enter() = 0; virtual void enter() = 0;
virtual uint8 read(uint8 addr) = 0; virtual uint8 read(uint8 addr) = 0;
virtual void write(uint8 addr, uint8 data) = 0; virtual void write(uint8 addr, uint8 data) = 0;
virtual void power() = 0; virtual void power() = 0;
virtual void reset() = 0; virtual void reset() = 0;
DSP() {} DSP() {}
virtual ~DSP() {} virtual ~DSP() {}
}; };

View File

@ -59,4 +59,4 @@ void sDSP::brr_decode(voice_t &v) {
} }
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -49,4 +49,4 @@ inline bool sDSP::counter_poll(unsigned rate) {
return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0; return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -132,4 +132,4 @@ void sDSP::echo_30() {
echo_write(1); echo_write(1);
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -59,4 +59,4 @@ void sDSP::envelope_run(voice_t &v) {
if(counter_poll(rate) == true) v.env = env; if(counter_poll(rate) == true) v.env = env;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -51,4 +51,4 @@ int sDSP::gaussian_interpolate(const voice_t &v) {
return sclamp<16>(output) & ~1; return sclamp<16>(output) & ~1;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -32,4 +32,4 @@ void sDSP::misc_30() {
} }
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -326,4 +326,3 @@ sDSP::~sDSP() {
} }
}; };

View File

@ -171,4 +171,4 @@ void sDSP::voice_9(voice_t &v) {
VREG(envx) = (uint8)state.envx_buf; VREG(envx) = (uint8)state.envx_buf;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -28,4 +28,3 @@ namespace SNES {
#include "chip/chip.hpp" #include "chip/chip.hpp"
#include "cartridge/cartridge.hpp" #include "cartridge/cartridge.hpp"
}; };

View File

@ -1,8 +1,13 @@
DirectFilter filter_direct; DirectFilter filter_direct;
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render( void DirectFilter::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
pitch >>= 1; pitch >>= 1;
outpitch >>= 2; outpitch >>= 2;
@ -24,7 +29,4 @@ void DirectFilter::render(
input += pitch - width; input += pitch - width;
output += outpitch - width; output += outpitch - width;
} }
outwidth = width;
outheight = height;
} }

View File

@ -1,6 +1,7 @@
class DirectFilter : public Filter { class DirectFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
}; };
extern DirectFilter filter_direct; extern DirectFilter filter_direct;

View File

@ -4,30 +4,26 @@ void FilterInterface::set(FilterInterface::FilterType type) {
active_filter = type; active_filter = type;
} }
void FilterInterface::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
switch(active_filter) { default:
case Direct: return filter_direct.size(outwidth, outheight, width, height);
case Scanline: return filter_scanline.size(outwidth, outheight, width, height);
case Scale2x: return filter_scale2x.size(outwidth, outheight, width, height);
case HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
void FilterInterface::render( void FilterInterface::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
switch(active_filter) { default: switch(active_filter) { default:
case Direct: { case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
} break; case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
case Scanline: { case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
filter_scanline.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case Scale2x: {
filter_scale2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case HQ2x: {
filter_hq2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case NTSC: {
filter_ntsc.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
} }
} }

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