mirror of https://github.com/bsnes-emu/bsnes.git
First version split into asnes and bsnes.
This commit is contained in:
commit
165f1e74b5
|
@ -0,0 +1,91 @@
|
||||||
|
include nall/Makefile
|
||||||
|
snes := asnes
|
||||||
|
ui := qt
|
||||||
|
|
||||||
|
# compiler
|
||||||
|
c := $(compiler) -std=gnu99
|
||||||
|
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||||
|
flags := -O3 -fomit-frame-pointer -I. -I$(snes)
|
||||||
|
link :=
|
||||||
|
objects :=
|
||||||
|
|
||||||
|
# profile-guided instrumentation
|
||||||
|
# flags += -fprofile-generate
|
||||||
|
# link += -lgcov
|
||||||
|
|
||||||
|
# profile-guided optimization
|
||||||
|
# flags += -fprofile-use
|
||||||
|
|
||||||
|
# platform
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
link += -s -ldl -lX11 -lXext
|
||||||
|
else ifeq ($(platform),osx)
|
||||||
|
else ifeq ($(platform),win)
|
||||||
|
link += -mwindows
|
||||||
|
# link += -mconsole
|
||||||
|
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
|
||||||
|
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||||
|
else
|
||||||
|
unknown_platform: help;
|
||||||
|
endif
|
||||||
|
|
||||||
|
# implicit rules
|
||||||
|
compile = \
|
||||||
|
$(strip \
|
||||||
|
$(if $(filter %.c,$<), \
|
||||||
|
$(c) $(flags) $1 -c $< -o $@, \
|
||||||
|
$(if $(filter %.cpp,$<), \
|
||||||
|
$(cpp) $(flags) $1 -c $< -o $@ \
|
||||||
|
) \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
%.o: $<; $(call compile)
|
||||||
|
|
||||||
|
all: build;
|
||||||
|
|
||||||
|
include $(snes)/Makefile
|
||||||
|
include $(ui)/Makefile
|
||||||
|
|
||||||
|
objects := $(patsubst %,obj/%.o,$(objects))
|
||||||
|
|
||||||
|
# targets
|
||||||
|
build: ui_build $(objects)
|
||||||
|
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 out/$(snes) $(objects) $(link))
|
||||||
|
endif
|
||||||
|
|
||||||
|
install:
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes
|
||||||
|
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||||
|
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||||
|
endif
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
rm $(DESTDIR)$(prefix)/bin/bsnes
|
||||||
|
rm $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||||
|
rm $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean: ui_clean
|
||||||
|
-@$(call delete,obj/*.o)
|
||||||
|
-@$(call delete,obj/*.a)
|
||||||
|
-@$(call delete,obj/*.so)
|
||||||
|
-@$(call delete,obj/*.dylib)
|
||||||
|
-@$(call delete,obj/*.dll)
|
||||||
|
-@$(call delete,*.res)
|
||||||
|
-@$(call delete,*.pgd)
|
||||||
|
-@$(call delete,*.pgc)
|
||||||
|
-@$(call delete,*.ilk)
|
||||||
|
-@$(call delete,*.pdb)
|
||||||
|
-@$(call delete,*.manifest)
|
||||||
|
|
||||||
|
archive-all:
|
||||||
|
tar -cjf snes-`date +%Y%m%d`.tar.bz2 asnes bsnes libco nall obj out qt ruby Makefile sync.sh
|
||||||
|
|
||||||
|
help:;
|
|
@ -0,0 +1,77 @@
|
||||||
|
snes_objects := libco
|
||||||
|
snes_objects += snes-system
|
||||||
|
snes_objects += snes-cartridge snes-cheat
|
||||||
|
snes_objects += snes-memory snes-cpucore snes-cpu snes-smpcore snes-smp snes-dsp snes-ppu
|
||||||
|
snes_objects += snes-supergameboy snes-superfx snes-sa1
|
||||||
|
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
|
||||||
|
snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4
|
||||||
|
snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018
|
||||||
|
snes_objects += snes-msu1 snes-serial
|
||||||
|
objects += $(snes_objects)
|
||||||
|
|
||||||
|
obj/libco.o : libco/libco.c libco/*
|
||||||
|
obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/*
|
||||||
|
|
||||||
|
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
|
||||||
|
obj/snes-memory.o : $(snes)/memory/memory.cpp $(snes)/memory/*
|
||||||
|
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
|
||||||
|
obj/snes-cpu.o : $(snes)/cpu/cpu.cpp $(snes)/cpu/*
|
||||||
|
obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/)
|
||||||
|
obj/snes-smp.o : $(snes)/smp/smp.cpp $(snes)/smp/*
|
||||||
|
obj/snes-dsp.o : $(snes)/dsp/dsp.cpp $(snes)/dsp/*
|
||||||
|
obj/snes-ppu.o : $(snes)/ppu/ppu.cpp $(snes)/ppu/*
|
||||||
|
obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
|
||||||
|
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
|
||||||
|
|
||||||
|
obj/snes-supergameboy.o: $(snes)/chip/supergameboy/supergameboy.cpp $(call rwildcard,$(snes)/chip/supergameboy/)
|
||||||
|
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
|
||||||
|
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
|
||||||
|
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/*
|
||||||
|
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
|
||||||
|
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
|
||||||
|
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
|
||||||
|
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
|
||||||
|
obj/snes-dsp1.o : $(snes)/chip/dsp1/dsp1.cpp $(snes)/chip/dsp1/*
|
||||||
|
obj/snes-dsp2.o : $(snes)/chip/dsp2/dsp2.cpp $(snes)/chip/dsp2/*
|
||||||
|
obj/snes-dsp3.o : $(snes)/chip/dsp3/dsp3.cpp $(snes)/chip/dsp3/*
|
||||||
|
obj/snes-dsp4.o : $(snes)/chip/dsp4/dsp4.cpp $(snes)/chip/dsp4/*
|
||||||
|
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
|
||||||
|
obj/snes-st0010.o : $(snes)/chip/st0010/st0010.cpp $(snes)/chip/st0010/*
|
||||||
|
obj/snes-st0011.o : $(snes)/chip/st0011/st0011.cpp $(snes)/chip/st0011/*
|
||||||
|
obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
|
||||||
|
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
|
||||||
|
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
|
||||||
|
|
||||||
|
###########
|
||||||
|
# library #
|
||||||
|
###########
|
||||||
|
|
||||||
|
snes_objects := $(patsubst %,obj/%.o,$(snes_objects))
|
||||||
|
|
||||||
|
library: $(snes_objects) obj/libsnes.o
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||||
|
$(cpp) -o obj/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
|
||||||
|
else ifeq ($(platform),osx)
|
||||||
|
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||||
|
$(cpp) -o obj/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
|
||||||
|
else ifeq ($(platform),win)
|
||||||
|
$(cpp) -o obj/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
library-install:
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
install -D -m 755 obj/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||||
|
install -D -m 755 obj/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||||
|
ldconfig -n $(DESTDIR)$(prefix)/lib
|
||||||
|
else ifeq ($(platform),osx)
|
||||||
|
cp obj/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||||
|
endif
|
||||||
|
|
||||||
|
library-uninstall:
|
||||||
|
ifeq ($(platform),x)
|
||||||
|
rm $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||||
|
rm $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||||
|
else ifeq ($(platform),osx)
|
||||||
|
rm /usr/local/lib/libsnes.dylib
|
||||||
|
endif
|
|
@ -0,0 +1,85 @@
|
||||||
|
#ifdef SYSTEM_CPP
|
||||||
|
|
||||||
|
Audio audio;
|
||||||
|
|
||||||
|
void Audio::coprocessor_enable(bool state) {
|
||||||
|
coprocessor = state;
|
||||||
|
|
||||||
|
dsp_rdoffset = cop_rdoffset = 0;
|
||||||
|
dsp_wroffset = cop_wroffset = 0;
|
||||||
|
dsp_length = cop_length = 0;
|
||||||
|
|
||||||
|
r_sum_l = r_sum_r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::coprocessor_frequency(double input_frequency) {
|
||||||
|
double output_frequency;
|
||||||
|
output_frequency = system.apu_frequency() / 768.0;
|
||||||
|
r_step = input_frequency / output_frequency;
|
||||||
|
r_frac = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::sample(int16 left, int16 right) {
|
||||||
|
if(coprocessor == false) {
|
||||||
|
system.interface->audio_sample(left, right);
|
||||||
|
} else {
|
||||||
|
dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16);
|
||||||
|
dsp_wroffset = (dsp_wroffset + 1) & 32767;
|
||||||
|
dsp_length = (dsp_length + 1) & 32767;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::coprocessor_sample(int16 left, int16 right) {
|
||||||
|
if(r_frac >= 1.0) {
|
||||||
|
r_frac -= 1.0;
|
||||||
|
r_sum_l += left;
|
||||||
|
r_sum_r += right;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_sum_l += left * r_frac;
|
||||||
|
r_sum_r += right * r_frac;
|
||||||
|
|
||||||
|
uint16 output_left = sclamp<16>(int(r_sum_l / r_step));
|
||||||
|
uint16 output_right = sclamp<16>(int(r_sum_r / r_step));
|
||||||
|
|
||||||
|
double first = 1.0 - r_frac;
|
||||||
|
r_sum_l = left * first;
|
||||||
|
r_sum_r = right * first;
|
||||||
|
r_frac = r_step - first;
|
||||||
|
|
||||||
|
cop_buffer[cop_wroffset] = (output_left << 0) + (output_right << 16);
|
||||||
|
cop_wroffset = (cop_wroffset + 1) & 32767;
|
||||||
|
cop_length = (cop_length + 1) & 32767;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::flush() {
|
||||||
|
while(dsp_length > 0 && cop_length > 0) {
|
||||||
|
uint32 dsp_sample = dsp_buffer[dsp_rdoffset];
|
||||||
|
uint32 cop_sample = cop_buffer[cop_rdoffset];
|
||||||
|
|
||||||
|
dsp_rdoffset = (dsp_rdoffset + 1) & 32767;
|
||||||
|
cop_rdoffset = (cop_rdoffset + 1) & 32767;
|
||||||
|
|
||||||
|
dsp_length--;
|
||||||
|
cop_length--;
|
||||||
|
|
||||||
|
int dsp_left = (int16)(dsp_sample >> 0);
|
||||||
|
int dsp_right = (int16)(dsp_sample >> 16);
|
||||||
|
|
||||||
|
int cop_left = (int16)(cop_sample >> 0);
|
||||||
|
int cop_right = (int16)(cop_sample >> 16);
|
||||||
|
|
||||||
|
system.interface->audio_sample(
|
||||||
|
sclamp<16>((dsp_left + cop_left ) / 2),
|
||||||
|
sclamp<16>((dsp_right + cop_right) / 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,22 @@
|
||||||
|
class Audio {
|
||||||
|
public:
|
||||||
|
void coprocessor_enable(bool state);
|
||||||
|
void coprocessor_frequency(double frequency);
|
||||||
|
void sample(int16 left, int16 right);
|
||||||
|
void coprocessor_sample(int16 left, int16 right);
|
||||||
|
void init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool coprocessor;
|
||||||
|
uint32 dsp_buffer[32768], cop_buffer[32768];
|
||||||
|
unsigned dsp_rdoffset, cop_rdoffset;
|
||||||
|
unsigned dsp_wroffset, cop_wroffset;
|
||||||
|
unsigned dsp_length, cop_length;
|
||||||
|
|
||||||
|
double r_step, r_frac;
|
||||||
|
int r_sum_l, r_sum_r;
|
||||||
|
|
||||||
|
void flush();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Audio audio;
|
|
@ -0,0 +1,144 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#include <nall/crc32.hpp>
|
||||||
|
#include <nall/sha256.hpp>
|
||||||
|
|
||||||
|
#define CARTRIDGE_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
#include "xml.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
MappedRAM cartrom, cartram, cartrtc;
|
||||||
|
MappedRAM bsxflash, bsxram, bsxpram;
|
||||||
|
MappedRAM stArom, stAram;
|
||||||
|
MappedRAM stBrom, stBram;
|
||||||
|
MappedRAM gbrom, gbram, gbrtc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Cartridge cartridge;
|
||||||
|
|
||||||
|
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||||
|
mode = cartridge_mode;
|
||||||
|
region = Region::NTSC;
|
||||||
|
ram_size = 0;
|
||||||
|
spc7110_data_rom_offset = 0x100000;
|
||||||
|
supergameboy_version = SuperGameBoyVersion::Version1;
|
||||||
|
supergameboy_ram_size = 0;
|
||||||
|
supergameboy_rtc_size = 0;
|
||||||
|
serial_baud_rate = 57600;
|
||||||
|
|
||||||
|
has_bsx_slot = false;
|
||||||
|
has_superfx = false;
|
||||||
|
has_sa1 = false;
|
||||||
|
has_srtc = false;
|
||||||
|
has_sdd1 = false;
|
||||||
|
has_spc7110 = false;
|
||||||
|
has_spc7110rtc = false;
|
||||||
|
has_cx4 = false;
|
||||||
|
has_dsp1 = false;
|
||||||
|
has_dsp2 = false;
|
||||||
|
has_dsp3 = false;
|
||||||
|
has_dsp4 = false;
|
||||||
|
has_obc1 = false;
|
||||||
|
has_st0010 = false;
|
||||||
|
has_st0011 = false;
|
||||||
|
has_st0018 = false;
|
||||||
|
has_msu1 = false;
|
||||||
|
has_serial = false;
|
||||||
|
|
||||||
|
parse_xml(xml_list);
|
||||||
|
|
||||||
|
if(ram_size > 0) {
|
||||||
|
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has_srtc || has_spc7110rtc) {
|
||||||
|
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode == Mode::Bsx) {
|
||||||
|
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
|
||||||
|
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode == Mode::SufamiTurbo) {
|
||||||
|
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||||
|
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode == Mode::SuperGameBoy) {
|
||||||
|
if(memory::gbrom.data()) {
|
||||||
|
if(supergameboy_ram_size) memory::gbram.map(allocate<uint8_t>(supergameboy_ram_size, 0xff), supergameboy_ram_size);
|
||||||
|
if(supergameboy_rtc_size) memory::gbrtc.map(allocate<uint8_t>(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrom.write_protect(true);
|
||||||
|
memory::cartram.write_protect(false);
|
||||||
|
memory::cartrtc.write_protect(false);
|
||||||
|
memory::bsxflash.write_protect(true);
|
||||||
|
memory::bsxram.write_protect(false);
|
||||||
|
memory::bsxpram.write_protect(false);
|
||||||
|
memory::stArom.write_protect(true);
|
||||||
|
memory::stAram.write_protect(false);
|
||||||
|
memory::stBrom.write_protect(true);
|
||||||
|
memory::stBram.write_protect(false);
|
||||||
|
memory::gbrom.write_protect(true);
|
||||||
|
memory::gbram.write_protect(false);
|
||||||
|
memory::gbrtc.write_protect(false);
|
||||||
|
|
||||||
|
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
|
||||||
|
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
|
||||||
|
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
|
||||||
|
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
|
||||||
|
if(memory::gbrom.size() != 0 && memory::gbrom.size() != ~0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
|
||||||
|
crc32 = ~checksum;
|
||||||
|
|
||||||
|
sha256_ctx sha;
|
||||||
|
uint8_t shahash[32];
|
||||||
|
sha256_init(&sha);
|
||||||
|
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
|
||||||
|
sha256_final(&sha);
|
||||||
|
sha256_hash(&sha, shahash);
|
||||||
|
|
||||||
|
string hash;
|
||||||
|
foreach(n, shahash) hash << strhex<2>(n);
|
||||||
|
sha256 = hash;
|
||||||
|
|
||||||
|
bus.load_cart();
|
||||||
|
system.serialize_init();
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::unload() {
|
||||||
|
memory::cartrom.reset();
|
||||||
|
memory::cartram.reset();
|
||||||
|
memory::cartrtc.reset();
|
||||||
|
memory::bsxflash.reset();
|
||||||
|
memory::bsxram.reset();
|
||||||
|
memory::bsxpram.reset();
|
||||||
|
memory::stArom.reset();
|
||||||
|
memory::stAram.reset();
|
||||||
|
memory::stBrom.reset();
|
||||||
|
memory::stBram.reset();
|
||||||
|
memory::gbrom.reset();
|
||||||
|
memory::gbram.reset();
|
||||||
|
memory::gbrtc.reset();
|
||||||
|
|
||||||
|
if(loaded == false) return;
|
||||||
|
bus.unload_cart();
|
||||||
|
loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::Cartridge() {
|
||||||
|
loaded = false;
|
||||||
|
unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::~Cartridge() {
|
||||||
|
unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
class Cartridge : property<Cartridge> {
|
||||||
|
public:
|
||||||
|
enum class Mode : unsigned {
|
||||||
|
Normal,
|
||||||
|
BsxSlotted,
|
||||||
|
Bsx,
|
||||||
|
SufamiTurbo,
|
||||||
|
SuperGameBoy,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Region : unsigned {
|
||||||
|
NTSC,
|
||||||
|
PAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SuperGameBoyVersion : unsigned {
|
||||||
|
Version1,
|
||||||
|
Version2,
|
||||||
|
};
|
||||||
|
|
||||||
|
//assigned externally to point to file-system datafiles (msu1 and serial)
|
||||||
|
//example: "/path/to/filename.sfc" would set this to "/path/to/filename"
|
||||||
|
readwrite<string> basename;
|
||||||
|
|
||||||
|
readonly<bool> loaded;
|
||||||
|
readonly<unsigned> crc32;
|
||||||
|
readonly<string> sha256;
|
||||||
|
|
||||||
|
readonly<Mode> mode;
|
||||||
|
readonly<Region> region;
|
||||||
|
readonly<unsigned> ram_size;
|
||||||
|
readonly<unsigned> spc7110_data_rom_offset;
|
||||||
|
readonly<SuperGameBoyVersion> supergameboy_version;
|
||||||
|
readonly<unsigned> supergameboy_ram_size;
|
||||||
|
readonly<unsigned> supergameboy_rtc_size;
|
||||||
|
readonly<unsigned> serial_baud_rate;
|
||||||
|
|
||||||
|
readonly<bool> has_bsx_slot;
|
||||||
|
readonly<bool> has_superfx;
|
||||||
|
readonly<bool> has_sa1;
|
||||||
|
readonly<bool> has_srtc;
|
||||||
|
readonly<bool> has_sdd1;
|
||||||
|
readonly<bool> has_spc7110;
|
||||||
|
readonly<bool> has_spc7110rtc;
|
||||||
|
readonly<bool> has_cx4;
|
||||||
|
readonly<bool> has_dsp1;
|
||||||
|
readonly<bool> has_dsp2;
|
||||||
|
readonly<bool> has_dsp3;
|
||||||
|
readonly<bool> has_dsp4;
|
||||||
|
readonly<bool> has_obc1;
|
||||||
|
readonly<bool> has_st0010;
|
||||||
|
readonly<bool> has_st0011;
|
||||||
|
readonly<bool> has_st0018;
|
||||||
|
readonly<bool> has_msu1;
|
||||||
|
readonly<bool> has_serial;
|
||||||
|
|
||||||
|
struct Mapping {
|
||||||
|
Memory *memory;
|
||||||
|
MMIO *mmio;
|
||||||
|
Bus::MapMode mode;
|
||||||
|
unsigned banklo;
|
||||||
|
unsigned bankhi;
|
||||||
|
unsigned addrlo;
|
||||||
|
unsigned addrhi;
|
||||||
|
unsigned offset;
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
|
Mapping();
|
||||||
|
Mapping(Memory&);
|
||||||
|
Mapping(MMIO&);
|
||||||
|
};
|
||||||
|
array<Mapping> mapping;
|
||||||
|
|
||||||
|
void load(Mode, const lstring&);
|
||||||
|
void unload();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
Cartridge();
|
||||||
|
~Cartridge();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parse_xml(const lstring&);
|
||||||
|
void parse_xml_cartridge(const char*);
|
||||||
|
void parse_xml_bsx(const char*);
|
||||||
|
void parse_xml_sufami_turbo(const char*, bool);
|
||||||
|
void parse_xml_gameboy(const char*);
|
||||||
|
|
||||||
|
void xml_parse_rom(xml_element&);
|
||||||
|
void xml_parse_ram(xml_element&);
|
||||||
|
void xml_parse_superfx(xml_element&);
|
||||||
|
void xml_parse_sa1(xml_element&);
|
||||||
|
void xml_parse_bsx(xml_element&);
|
||||||
|
void xml_parse_sufamiturbo(xml_element&);
|
||||||
|
void xml_parse_supergameboy(xml_element&);
|
||||||
|
void xml_parse_srtc(xml_element&);
|
||||||
|
void xml_parse_sdd1(xml_element&);
|
||||||
|
void xml_parse_spc7110(xml_element&);
|
||||||
|
void xml_parse_cx4(xml_element&);
|
||||||
|
void xml_parse_necdsp(xml_element&);
|
||||||
|
void xml_parse_obc1(xml_element&);
|
||||||
|
void xml_parse_setadsp(xml_element&);
|
||||||
|
void xml_parse_setarisc(xml_element&);
|
||||||
|
void xml_parse_msu1(xml_element&);
|
||||||
|
void xml_parse_serial(xml_element&);
|
||||||
|
|
||||||
|
void xml_parse_address(Mapping&, const string&);
|
||||||
|
void xml_parse_mode(Mapping&, const string&);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
extern MappedRAM cartrom, cartram, cartrtc;
|
||||||
|
extern MappedRAM bsxflash, bsxram, bsxpram;
|
||||||
|
extern MappedRAM stArom, stAram;
|
||||||
|
extern MappedRAM stBrom, stBram;
|
||||||
|
extern MappedRAM gbrom, gbram, gbrtc;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Cartridge cartridge;
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifdef CARTRIDGE_CPP
|
||||||
|
|
||||||
|
void Cartridge::serialize(serializer &s) {
|
||||||
|
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
|
||||||
|
s.array(memory::cartram.data(), memory::cartram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
|
||||||
|
s.array(memory::cartrtc.data(), memory::cartrtc.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
|
||||||
|
s.array(memory::bsxram.data(), memory::bsxram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
|
||||||
|
s.array(memory::bsxpram.data(), memory::bsxpram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
|
||||||
|
s.array(memory::stAram.data(), memory::stAram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
|
||||||
|
s.array(memory::stBram.data(), memory::stBram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
|
||||||
|
s.array(memory::gbram.data(), memory::gbram.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
|
||||||
|
s.array(memory::gbrtc.data(), memory::gbrtc.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,671 @@
|
||||||
|
#ifdef CARTRIDGE_CPP
|
||||||
|
|
||||||
|
void Cartridge::parse_xml(const lstring &list) {
|
||||||
|
mapping.reset();
|
||||||
|
parse_xml_cartridge(list[0]);
|
||||||
|
|
||||||
|
if(mode == Mode::BsxSlotted) {
|
||||||
|
parse_xml_bsx(list[1]);
|
||||||
|
} else if(mode == Mode::Bsx) {
|
||||||
|
parse_xml_bsx(list[1]);
|
||||||
|
} else if(mode == Mode::SufamiTurbo) {
|
||||||
|
parse_xml_sufami_turbo(list[1], 0);
|
||||||
|
parse_xml_sufami_turbo(list[2], 1);
|
||||||
|
} else if(mode == Mode::SuperGameBoy) {
|
||||||
|
parse_xml_gameboy(list[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::parse_xml_cartridge(const char *data) {
|
||||||
|
xml_element document = xml_parse(data);
|
||||||
|
if(document.element.size() == 0) return;
|
||||||
|
|
||||||
|
foreach(head, document.element) {
|
||||||
|
if(head.name == "cartridge") {
|
||||||
|
foreach(attr, head.attribute) {
|
||||||
|
if(attr.name == "region") {
|
||||||
|
if(attr.content == "NTSC") region = Region::NTSC;
|
||||||
|
if(attr.content == "PAL") region = Region::PAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(node, head.element) {
|
||||||
|
if(node.name == "rom") xml_parse_rom(node);
|
||||||
|
if(node.name == "ram") xml_parse_ram(node);
|
||||||
|
if(node.name == "superfx") xml_parse_superfx(node);
|
||||||
|
if(node.name == "sa1") xml_parse_sa1(node);
|
||||||
|
if(node.name == "bsx") xml_parse_bsx(node);
|
||||||
|
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
|
||||||
|
if(node.name == "supergameboy") xml_parse_supergameboy(node);
|
||||||
|
if(node.name == "srtc") xml_parse_srtc(node);
|
||||||
|
if(node.name == "sdd1") xml_parse_sdd1(node);
|
||||||
|
if(node.name == "spc7110") xml_parse_spc7110(node);
|
||||||
|
if(node.name == "cx4") xml_parse_cx4(node);
|
||||||
|
if(node.name == "necdsp") xml_parse_necdsp(node);
|
||||||
|
if(node.name == "obc1") xml_parse_obc1(node);
|
||||||
|
if(node.name == "setadsp") xml_parse_setadsp(node);
|
||||||
|
if(node.name == "setarisc") xml_parse_setarisc(node);
|
||||||
|
if(node.name == "msu1") xml_parse_msu1(node);
|
||||||
|
if(node.name == "serial") xml_parse_serial(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::parse_xml_bsx(const char *data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::parse_xml_gameboy(const char *data) {
|
||||||
|
xml_element document = xml_parse(data);
|
||||||
|
if(document.element.size() == 0) return;
|
||||||
|
|
||||||
|
foreach(head, document.element) {
|
||||||
|
if(head.name == "cartridge") {
|
||||||
|
foreach(attr, head.attribute) {
|
||||||
|
if(attr.name == "rtc") {
|
||||||
|
supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(leaf, head.element) {
|
||||||
|
if(leaf.name == "ram") {
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "size") {
|
||||||
|
supergameboy_ram_size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_rom(xml_element &root) {
|
||||||
|
foreach(leaf, root.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::cartrom);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_ram(xml_element &root) {
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "size") ram_size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(leaf, root.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::cartram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||||
|
has_superfx = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "rom") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::fxrom);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "ram") {
|
||||||
|
foreach(attr, node.attribute) {
|
||||||
|
if(attr.name == "size") ram_size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::fxram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(superfx);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||||
|
has_sa1 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "rom") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::vsprom);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "iram") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::cpuiram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "bwram") {
|
||||||
|
foreach(attr, node.attribute) {
|
||||||
|
if(attr.name == "size") ram_size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::cc1bwram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(sa1);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||||
|
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "slot") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(memory::bsxflash);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(bsxcart);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||||
|
if(mode != Mode::SufamiTurbo) return;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "slot") {
|
||||||
|
bool slotid = 0;
|
||||||
|
foreach(attr, node.attribute) {
|
||||||
|
if(attr.name == "id") {
|
||||||
|
if(attr.content == "A") slotid = 0;
|
||||||
|
if(attr.content == "B") slotid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(slot, node.element) {
|
||||||
|
if(slot.name == "rom") {
|
||||||
|
foreach(leaf, slot.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(slotid == 0 ? memory::stArom : memory::stBrom);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
if(m.memory->size() > 0) mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(slot.name == "ram") {
|
||||||
|
foreach(leaf, slot.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(slotid == 0 ? memory::stAram : memory::stBram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
if(m.memory->size() > 0) mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_supergameboy(xml_element &root) {
|
||||||
|
if(mode != Mode::SuperGameBoy) return;
|
||||||
|
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "revision") {
|
||||||
|
if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
|
||||||
|
if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m((Memory&)supergameboy);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_srtc(xml_element &root) {
|
||||||
|
has_srtc = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(srtc);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_sdd1(xml_element &root) {
|
||||||
|
has_sdd1 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mcu") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m((Memory&)sdd1);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m((MMIO&)sdd1);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||||
|
has_spc7110 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "dcu") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(spc7110dcu);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mcu") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(spc7110mcu);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "offset") spc7110_data_rom_offset = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(spc7110);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "ram") {
|
||||||
|
foreach(attr, node.attribute) {
|
||||||
|
if(attr.name == "size") ram_size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(spc7110ram);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||||
|
if(attr.name == "offset") m.offset = strhex(attr.content);
|
||||||
|
if(attr.name == "size") m.size = strhex(attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "rtc") {
|
||||||
|
has_spc7110rtc = true;
|
||||||
|
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(spc7110);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_cx4(xml_element &root) {
|
||||||
|
has_cx4 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(cx4);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||||
|
unsigned program = 0;
|
||||||
|
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "program") {
|
||||||
|
if(attr.content == "DSP-1" || attr.content == "DSP-1A" || attr.content == "DSP-1B") {
|
||||||
|
program = 1;
|
||||||
|
has_dsp1 = true;
|
||||||
|
} else if(attr.content == "DSP-2") {
|
||||||
|
program = 2;
|
||||||
|
has_dsp2 = true;
|
||||||
|
} else if(attr.content == "DSP-3") {
|
||||||
|
program = 3;
|
||||||
|
has_dsp3 = true;
|
||||||
|
} else if(attr.content == "DSP-4") {
|
||||||
|
program = 4;
|
||||||
|
has_dsp4 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory *dr[5] = { 0, &dsp1dr, &dsp2dr, &dsp3, &dsp4 };
|
||||||
|
Memory *sr[5] = { 0, &dsp1sr, &dsp2sr, &dsp3, &dsp4 };
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "dr" && dr[program]) {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(*dr[program]);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(node.name == "sr" && sr[program]) {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(*sr[program]);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_obc1(xml_element &root) {
|
||||||
|
has_obc1 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(obc1);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_setadsp(xml_element &root) {
|
||||||
|
unsigned program = 0;
|
||||||
|
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "program") {
|
||||||
|
if(attr.content == "ST-0010") {
|
||||||
|
program = 1;
|
||||||
|
has_st0010 = true;
|
||||||
|
} else if(attr.content == "ST-0011") {
|
||||||
|
program = 2;
|
||||||
|
has_st0011 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory *map[3] = { 0, &st0010, 0 };
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio" && map[program]) {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(*map[program]);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_setarisc(xml_element &root) {
|
||||||
|
unsigned program = 0;
|
||||||
|
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "program") {
|
||||||
|
if(attr.content == "ST-0018") {
|
||||||
|
program = 1;
|
||||||
|
has_st0018 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MMIO *map[2] = { 0, &st0018 };
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio" && map[program]) {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(*map[program]);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_msu1(xml_element &root) {
|
||||||
|
has_msu1 = true;
|
||||||
|
|
||||||
|
foreach(node, root.element) {
|
||||||
|
if(node.name == "mmio") {
|
||||||
|
foreach(leaf, node.element) {
|
||||||
|
if(leaf.name == "map") {
|
||||||
|
Mapping m(msu1);
|
||||||
|
foreach(attr, leaf.attribute) {
|
||||||
|
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||||
|
}
|
||||||
|
mapping.append(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_serial(xml_element &root) {
|
||||||
|
has_serial = true;
|
||||||
|
|
||||||
|
foreach(attr, root.attribute) {
|
||||||
|
if(attr.name == "baud") {
|
||||||
|
serial_baud_rate = strunsigned(attr.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_address(Mapping &m, const string &data) {
|
||||||
|
lstring part;
|
||||||
|
part.split(":", data);
|
||||||
|
if(part.size() != 2) return;
|
||||||
|
|
||||||
|
lstring subpart;
|
||||||
|
subpart.split("-", part[0]);
|
||||||
|
if(subpart.size() == 1) {
|
||||||
|
m.banklo = strhex(subpart[0]);
|
||||||
|
m.bankhi = m.banklo;
|
||||||
|
} else if(subpart.size() == 2) {
|
||||||
|
m.banklo = strhex(subpart[0]);
|
||||||
|
m.bankhi = strhex(subpart[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
subpart.split("-", part[1]);
|
||||||
|
if(subpart.size() == 1) {
|
||||||
|
m.addrlo = strhex(subpart[0]);
|
||||||
|
m.addrhi = m.addrlo;
|
||||||
|
} else if(subpart.size() == 2) {
|
||||||
|
m.addrlo = strhex(subpart[0]);
|
||||||
|
m.addrhi = strhex(subpart[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
|
||||||
|
if(data == "direct") m.mode = Bus::MapMode::Direct;
|
||||||
|
else if(data == "linear") m.mode = Bus::MapMode::Linear;
|
||||||
|
else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::Mapping::Mapping() {
|
||||||
|
memory = 0;
|
||||||
|
mmio = 0;
|
||||||
|
mode = Bus::MapMode::Direct;
|
||||||
|
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::Mapping::Mapping(Memory &memory_) {
|
||||||
|
memory = &memory_;
|
||||||
|
mmio = 0;
|
||||||
|
mode = Bus::MapMode::Direct;
|
||||||
|
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::Mapping::Mapping(MMIO &mmio_) {
|
||||||
|
memory = 0;
|
||||||
|
mmio = &mmio_;
|
||||||
|
mode = Bus::MapMode::Direct;
|
||||||
|
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
bool Cheat::active() const { return cheat_enabled; }
|
||||||
|
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }
|
|
@ -0,0 +1,194 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define CHEAT_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
Cheat cheat;
|
||||||
|
|
||||||
|
bool Cheat::enabled() const {
|
||||||
|
return system_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::enable(bool state) {
|
||||||
|
system_enabled = state;
|
||||||
|
cheat_enabled = system_enabled && code_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cheat::synchronize() {
|
||||||
|
memset(bitmask, 0x00, sizeof bitmask);
|
||||||
|
code_enabled = false;
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < size(); i++) {
|
||||||
|
const CheatCode &code = operator[](i);
|
||||||
|
if(code.enabled == false) continue;
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||||
|
code_enabled = true;
|
||||||
|
|
||||||
|
unsigned addr = mirror(code.addr[n]);
|
||||||
|
bitmask[addr >> 3] |= 1 << (addr & 7);
|
||||||
|
if((addr & 0xffe000) == 0x7e0000) {
|
||||||
|
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||||
|
unsigned mirroraddr;
|
||||||
|
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||||
|
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||||
|
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||||
|
|
||||||
|
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||||
|
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cheat_enabled = system_enabled && code_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::read(unsigned addr, uint8 &data) const {
|
||||||
|
addr = mirror(addr);
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < size(); i++) {
|
||||||
|
const CheatCode &code = operator[](i);
|
||||||
|
if(code.enabled == false) continue;
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||||
|
if(addr == mirror(code.addr[n])) {
|
||||||
|
data = code.data[n];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cheat::Cheat() {
|
||||||
|
system_enabled = true;
|
||||||
|
synchronize();
|
||||||
|
}
|
||||||
|
|
||||||
|
//===============
|
||||||
|
//encode / decode
|
||||||
|
//===============
|
||||||
|
|
||||||
|
bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
|
||||||
|
string t = s;
|
||||||
|
t.lower();
|
||||||
|
|
||||||
|
#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 = 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 = Type::GameGenie;
|
||||||
|
t.transform("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ischr
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) {
|
||||||
|
char t[16];
|
||||||
|
|
||||||
|
if(type == Type::ProActionReplay) {
|
||||||
|
s = string(strhex<6>(addr), strhex<2>(data));
|
||||||
|
return true;
|
||||||
|
} else if(type == 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);
|
||||||
|
s = string(strhex<2>(data), strhex<2>(addr >> 16), "-", strhex<4>(addr & 0xffff));
|
||||||
|
s.transform("0123456789abcdef", "df4709156bc8a23e");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//========
|
||||||
|
//internal
|
||||||
|
//========
|
||||||
|
|
||||||
|
unsigned Cheat::mirror(unsigned addr) const {
|
||||||
|
//$00-3f|80-bf:0000-1fff -> $7e:0000-1fff
|
||||||
|
if((addr & 0x40e000) == 0x000000) return (0x7e0000 + (addr & 0x1fff));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//CheatCode
|
||||||
|
//=========
|
||||||
|
|
||||||
|
bool CheatCode::operator=(string s) {
|
||||||
|
addr.reset();
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
lstring list;
|
||||||
|
list.split("+", s.replace(" ", ""));
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < list.size(); i++) {
|
||||||
|
unsigned addr_;
|
||||||
|
uint8 data_;
|
||||||
|
Cheat::Type type_;
|
||||||
|
if(Cheat::decode(list[i], addr_, data_, type_) == false) {
|
||||||
|
addr.reset();
|
||||||
|
data.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.append(addr_);
|
||||||
|
data.append(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheatCode::CheatCode() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
struct CheatCode {
|
||||||
|
bool enabled;
|
||||||
|
array<unsigned> addr;
|
||||||
|
array<uint8> data;
|
||||||
|
|
||||||
|
bool operator=(string);
|
||||||
|
CheatCode();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Cheat : public linear_vector<CheatCode> {
|
||||||
|
public:
|
||||||
|
enum class Type : unsigned { ProActionReplay, GameGenie };
|
||||||
|
|
||||||
|
bool enabled() const;
|
||||||
|
void enable(bool);
|
||||||
|
void synchronize();
|
||||||
|
bool read(unsigned, uint8&) const;
|
||||||
|
|
||||||
|
inline bool active() const;
|
||||||
|
inline bool exists(unsigned addr) const;
|
||||||
|
|
||||||
|
Cheat();
|
||||||
|
|
||||||
|
static bool decode(const char*, unsigned&, uint8&, Type&);
|
||||||
|
static bool encode(string&, unsigned, uint8, Type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 bitmask[0x200000];
|
||||||
|
bool system_enabled;
|
||||||
|
bool code_enabled;
|
||||||
|
bool cheat_enabled;
|
||||||
|
unsigned mirror(unsigned) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Cheat cheat;
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define BSX_CPP
|
||||||
|
namespace SNES {
|
||||||
|
#include "bsx_base.cpp"
|
||||||
|
#include "bsx_cart.cpp"
|
||||||
|
#include "bsx_flash.cpp"
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
class BSXBase : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
uint8 r2188, r2189, r218a, r218b;
|
||||||
|
uint8 r218c, r218d, r218e, r218f;
|
||||||
|
uint8 r2190, r2191, r2192, r2193;
|
||||||
|
uint8 r2194, r2195, r2196, r2197;
|
||||||
|
uint8 r2198, r2199, r219a, r219b;
|
||||||
|
uint8 r219c, r219d, r219e, r219f;
|
||||||
|
|
||||||
|
uint8 r2192_counter;
|
||||||
|
uint8 r2192_hour, r2192_minute, r2192_second;
|
||||||
|
} regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BSXCart : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
BSXCart();
|
||||||
|
~BSXCart();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
uint8 r[16];
|
||||||
|
} regs;
|
||||||
|
|
||||||
|
void update_memory_map();
|
||||||
|
};
|
||||||
|
|
||||||
|
class BSXFlash : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
unsigned command;
|
||||||
|
uint8 write_old;
|
||||||
|
uint8 write_new;
|
||||||
|
|
||||||
|
bool flash_enable;
|
||||||
|
bool read_enable;
|
||||||
|
bool write_enable;
|
||||||
|
} regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern BSXBase bsxbase;
|
||||||
|
extern BSXCart bsxcart;
|
||||||
|
extern BSXFlash bsxflash;
|
|
@ -0,0 +1,140 @@
|
||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
BSXBase bsxbase;
|
||||||
|
|
||||||
|
void BSXBase::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::enable() {
|
||||||
|
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::reset() {
|
||||||
|
memset(®s, 0x00, sizeof regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXBase::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2188: return regs.r2188;
|
||||||
|
case 0x2189: return regs.r2189;
|
||||||
|
case 0x218a: return regs.r218a;
|
||||||
|
case 0x218c: return regs.r218c;
|
||||||
|
case 0x218e: return regs.r218e;
|
||||||
|
case 0x218f: return regs.r218f;
|
||||||
|
case 0x2190: return regs.r2190;
|
||||||
|
|
||||||
|
case 0x2192: {
|
||||||
|
unsigned counter = regs.r2192_counter++;
|
||||||
|
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
|
||||||
|
|
||||||
|
if(counter == 0) {
|
||||||
|
time_t rawtime;
|
||||||
|
time(&rawtime);
|
||||||
|
tm *t = localtime(&rawtime);
|
||||||
|
|
||||||
|
regs.r2192_hour = t->tm_hour;
|
||||||
|
regs.r2192_minute = t->tm_min;
|
||||||
|
regs.r2192_second = t->tm_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(counter) {
|
||||||
|
case 0: return 0x00; //???
|
||||||
|
case 1: return 0x00; //???
|
||||||
|
case 2: return 0x00; //???
|
||||||
|
case 3: return 0x00; //???
|
||||||
|
case 4: return 0x00; //???
|
||||||
|
case 5: return 0x01;
|
||||||
|
case 6: return 0x01;
|
||||||
|
case 7: return 0x00;
|
||||||
|
case 8: return 0x00;
|
||||||
|
case 9: return 0x00;
|
||||||
|
case 10: return regs.r2192_second;
|
||||||
|
case 11: return regs.r2192_minute;
|
||||||
|
case 12: return regs.r2192_hour;
|
||||||
|
case 13: return 0x00; //???
|
||||||
|
case 14: return 0x00; //???
|
||||||
|
case 15: return 0x00; //???
|
||||||
|
case 16: return 0x00; //???
|
||||||
|
case 17: return 0x00; //???
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2193: return regs.r2193 & ~0x0c;
|
||||||
|
case 0x2194: return regs.r2194;
|
||||||
|
case 0x2196: return regs.r2196;
|
||||||
|
case 0x2197: return regs.r2197;
|
||||||
|
case 0x2199: return regs.r2199;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2188: {
|
||||||
|
regs.r2188 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2189: {
|
||||||
|
regs.r2189 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218a: {
|
||||||
|
regs.r218a = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218b: {
|
||||||
|
regs.r218b = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218c: {
|
||||||
|
regs.r218c = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218e: {
|
||||||
|
regs.r218e = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x218f: {
|
||||||
|
regs.r218e >>= 1;
|
||||||
|
regs.r218e = regs.r218f - regs.r218e;
|
||||||
|
regs.r218f >>= 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2191: {
|
||||||
|
regs.r2191 = data;
|
||||||
|
regs.r2192_counter = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2192: {
|
||||||
|
regs.r2190 = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2193: {
|
||||||
|
regs.r2193 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2194: {
|
||||||
|
regs.r2194 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2197: {
|
||||||
|
regs.r2197 = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x2199: {
|
||||||
|
regs.r2199 = data;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
BSXCart bsxcart;
|
||||||
|
|
||||||
|
void BSXCart::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::reset() {
|
||||||
|
for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00;
|
||||||
|
regs.r[0x07] = 0x80;
|
||||||
|
regs.r[0x08] = 0x80;
|
||||||
|
|
||||||
|
update_memory_map();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::update_memory_map() {
|
||||||
|
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)memory::bsxpram;
|
||||||
|
|
||||||
|
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||||
|
//LoROM mapping
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||||
|
} else {
|
||||||
|
//HiROM mapping
|
||||||
|
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x03] & 0x80) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
|
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.r[0x05] & 0x80) == 0x00) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.r[0x06] & 0x80) == 0x00) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x07] & 0x80) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.r[0x08] & 0x80) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXCart::mmio_read(unsigned addr) {
|
||||||
|
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||||
|
uint8 n = (addr >> 16) & 15;
|
||||||
|
return regs.r[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||||
|
return memory::bsxram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXCart::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||||
|
uint8 n = (addr >> 16) & 15;
|
||||||
|
regs.r[n] = data;
|
||||||
|
if(n == 0x0e && data & 0x80) update_memory_map();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||||
|
return memory::bsxram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BSXCart::BSXCart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
BSXCart::~BSXCart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
#ifdef BSX_CPP
|
||||||
|
|
||||||
|
BSXFlash bsxflash;
|
||||||
|
|
||||||
|
void BSXFlash::init() {}
|
||||||
|
void BSXFlash::enable() {}
|
||||||
|
|
||||||
|
void BSXFlash::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXFlash::reset() {
|
||||||
|
regs.command = 0;
|
||||||
|
regs.write_old = 0x00;
|
||||||
|
regs.write_new = 0x00;
|
||||||
|
|
||||||
|
regs.flash_enable = false;
|
||||||
|
regs.read_enable = false;
|
||||||
|
regs.write_enable = false;
|
||||||
|
memory::bsxflash.write_protect(!regs.write_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BSXFlash::size() const {
|
||||||
|
return memory::bsxflash.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BSXFlash::read(unsigned addr) {
|
||||||
|
if(addr == 0x0002) {
|
||||||
|
if(regs.flash_enable) return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x5555) {
|
||||||
|
if(regs.flash_enable) return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
|
||||||
|
//read flash cartridge vendor information
|
||||||
|
switch(addr - 0xff00) {
|
||||||
|
case 0x00: return 0x4d;
|
||||||
|
case 0x01: return 0x00;
|
||||||
|
case 0x02: return 0x50;
|
||||||
|
case 0x03: return 0x00;
|
||||||
|
case 0x04: return 0x00;
|
||||||
|
case 0x05: return 0x00;
|
||||||
|
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
|
||||||
|
case 0x07: return 0x00;
|
||||||
|
default: return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory::bsxflash.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSXFlash::write(unsigned addr, uint8 data) {
|
||||||
|
//there exist both read-only and read-write BS-X flash cartridges ...
|
||||||
|
//unfortunately, the vendor info is not stored inside memory dumps
|
||||||
|
//of BS-X flashcarts, so it is impossible to determine whether a
|
||||||
|
//given flashcart is writeable.
|
||||||
|
//however, it has been observed that LoROM-mapped BS-X carts always
|
||||||
|
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||||
|
//read-only flashcarts.
|
||||||
|
//below is an unfortunately necessary workaround to this problem.
|
||||||
|
//if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
||||||
|
|
||||||
|
if((addr & 0xff0000) == 0) {
|
||||||
|
regs.write_old = regs.write_new;
|
||||||
|
regs.write_new = data;
|
||||||
|
|
||||||
|
if(regs.write_enable && regs.write_old == regs.write_new) {
|
||||||
|
return memory::bsxflash.write(addr, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(regs.write_enable) {
|
||||||
|
return memory::bsxflash.write(addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x0000) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
|
||||||
|
if((regs.command & 0xffff) == 0x38d0) {
|
||||||
|
regs.flash_enable = true;
|
||||||
|
regs.read_enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2aaa) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x5555) {
|
||||||
|
regs.command <<= 8;
|
||||||
|
regs.command |= data;
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa5570) {
|
||||||
|
regs.write_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa55a0) {
|
||||||
|
regs.write_old = 0x00;
|
||||||
|
regs.write_new = 0x00;
|
||||||
|
regs.flash_enable = true;
|
||||||
|
regs.write_enable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((regs.command & 0xffffff) == 0xaa55f0) {
|
||||||
|
regs.flash_enable = false;
|
||||||
|
regs.read_enable = false;
|
||||||
|
regs.write_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::bsxflash.write_protect(!regs.write_enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
struct Coprocessor : Processor {
|
||||||
|
alwaysinline void step(unsigned clocks);
|
||||||
|
alwaysinline void synchronize_cpu();
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <chip/supergameboy/supergameboy.hpp>
|
||||||
|
#include <chip/superfx/superfx.hpp>
|
||||||
|
#include <chip/sa1/sa1.hpp>
|
||||||
|
#include <chip/bsx/bsx.hpp>
|
||||||
|
#include <chip/srtc/srtc.hpp>
|
||||||
|
#include <chip/sdd1/sdd1.hpp>
|
||||||
|
#include <chip/spc7110/spc7110.hpp>
|
||||||
|
#include <chip/cx4/cx4.hpp>
|
||||||
|
#include <chip/dsp1/dsp1.hpp>
|
||||||
|
#include <chip/dsp2/dsp2.hpp>
|
||||||
|
#include <chip/dsp3/dsp3.hpp>
|
||||||
|
#include <chip/dsp4/dsp4.hpp>
|
||||||
|
#include <chip/obc1/obc1.hpp>
|
||||||
|
#include <chip/st0010/st0010.hpp>
|
||||||
|
#include <chip/st0011/st0011.hpp>
|
||||||
|
#include <chip/st0018/st0018.hpp>
|
||||||
|
#include <chip/msu1/msu1.hpp>
|
||||||
|
#include <chip/serial/serial.hpp>
|
||||||
|
|
||||||
|
void Coprocessor::step(unsigned clocks) {
|
||||||
|
clock += clocks * (uint64)cpu.frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Coprocessor::synchronize_cpu() {
|
||||||
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
//=============
|
||||||
|
//Cx4 emulation
|
||||||
|
//=============
|
||||||
|
//Used in Rockman X2/X3 (Megaman X2/X3)
|
||||||
|
//Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||||
|
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define CX4_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
Cx4 cx4;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#include "data.cpp"
|
||||||
|
#include "functions.cpp"
|
||||||
|
#include "oam.cpp"
|
||||||
|
#include "opcodes.cpp"
|
||||||
|
|
||||||
|
void Cx4::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::ldr(uint8 r) {
|
||||||
|
uint16 addr = 0x0080 + (r * 3);
|
||||||
|
return (reg[addr + 0] << 0)
|
||||||
|
| (reg[addr + 1] << 8)
|
||||||
|
| (reg[addr + 2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::str(uint8 r, uint32 data) {
|
||||||
|
uint16 addr = 0x0080 + (r * 3);
|
||||||
|
reg[addr + 0] = (data >> 0);
|
||||||
|
reg[addr + 1] = (data >> 8);
|
||||||
|
reg[addr + 2] = (data >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
|
||||||
|
int64 rx = x & 0xffffff;
|
||||||
|
int64 ry = y & 0xffffff;
|
||||||
|
if(rx & 0x800000)rx |= ~0x7fffff;
|
||||||
|
if(ry & 0x800000)ry |= ~0x7fffff;
|
||||||
|
|
||||||
|
rx *= ry;
|
||||||
|
|
||||||
|
rl = (rx) & 0xffffff;
|
||||||
|
rh = (rx >> 24) & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::sin(uint32 rx) {
|
||||||
|
r0 = rx & 0x1ff;
|
||||||
|
if(r0 & 0x100)r0 ^= 0x1ff;
|
||||||
|
if(r0 & 0x080)r0 ^= 0x0ff;
|
||||||
|
if(rx & 0x100) {
|
||||||
|
return sin_table[r0 + 0x80];
|
||||||
|
} else {
|
||||||
|
return sin_table[r0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::cos(uint32 rx) {
|
||||||
|
return sin(rx + 0x080);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::immediate_reg(uint32 start) {
|
||||||
|
r0 = ldr(0);
|
||||||
|
for(uint32 i = start; i < 48; i++) {
|
||||||
|
if((r0 & 0x0fff) < 0x0c00) {
|
||||||
|
ram[r0 & 0x0fff] = immediate_data[i];
|
||||||
|
}
|
||||||
|
r0++;
|
||||||
|
}
|
||||||
|
str(0, r0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::transfer_data() {
|
||||||
|
uint32 src;
|
||||||
|
uint16 dest, count;
|
||||||
|
|
||||||
|
src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
|
||||||
|
count = (reg[0x43]) | (reg[0x44] << 8);
|
||||||
|
dest = (reg[0x45]) | (reg[0x46] << 8);
|
||||||
|
|
||||||
|
for(uint32 i=0;i<count;i++) {
|
||||||
|
write(dest++, bus.read(src++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
|
||||||
|
if(addr < 0x0c00) {
|
||||||
|
//ram
|
||||||
|
ram[addr] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x1f00) {
|
||||||
|
//unmapped
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//command register
|
||||||
|
reg[addr & 0xff] = data;
|
||||||
|
|
||||||
|
if(addr == 0x1f47) {
|
||||||
|
//memory transfer
|
||||||
|
transfer_data();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x1f4f) {
|
||||||
|
//c4 command
|
||||||
|
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
|
||||||
|
//c4 test command
|
||||||
|
reg[0x80] = data >> 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(data) {
|
||||||
|
case 0x00: op00(); break;
|
||||||
|
case 0x01: op01(); break;
|
||||||
|
case 0x05: op05(); break;
|
||||||
|
case 0x0d: op0d(); break;
|
||||||
|
case 0x10: op10(); break;
|
||||||
|
case 0x13: op13(); break;
|
||||||
|
case 0x15: op15(); break;
|
||||||
|
case 0x1f: op1f(); break;
|
||||||
|
case 0x22: op22(); break;
|
||||||
|
case 0x25: op25(); break;
|
||||||
|
case 0x2d: op2d(); break;
|
||||||
|
case 0x40: op40(); break;
|
||||||
|
case 0x54: op54(); break;
|
||||||
|
case 0x5c: op5c(); break;
|
||||||
|
case 0x5e: op5e(); break;
|
||||||
|
case 0x60: op60(); break;
|
||||||
|
case 0x62: op62(); break;
|
||||||
|
case 0x64: op64(); break;
|
||||||
|
case 0x66: op66(); break;
|
||||||
|
case 0x68: op68(); break;
|
||||||
|
case 0x6a: op6a(); break;
|
||||||
|
case 0x6c: op6c(); break;
|
||||||
|
case 0x6e: op6e(); break;
|
||||||
|
case 0x70: op70(); break;
|
||||||
|
case 0x72: op72(); break;
|
||||||
|
case 0x74: op74(); break;
|
||||||
|
case 0x76: op76(); break;
|
||||||
|
case 0x78: op78(); break;
|
||||||
|
case 0x7a: op7a(); break;
|
||||||
|
case 0x7c: op7c(); break;
|
||||||
|
case 0x89: op89(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writeb(uint16 addr, uint8 data) {
|
||||||
|
write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writew(uint16 addr, uint16 data) {
|
||||||
|
write(addr + 0, data >> 0);
|
||||||
|
write(addr + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::writel(uint16 addr, uint32 data) {
|
||||||
|
write(addr + 0, data >> 0);
|
||||||
|
write(addr + 1, data >> 8);
|
||||||
|
write(addr + 2, data >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Cx4::read(unsigned addr) {
|
||||||
|
addr &= 0x1fff;
|
||||||
|
|
||||||
|
if(addr < 0x0c00) {
|
||||||
|
return ram[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x1f00) {
|
||||||
|
return reg[addr & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Cx4::readb(uint16 addr) {
|
||||||
|
return read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Cx4::readw(uint16 addr) {
|
||||||
|
return read(addr) | (read(addr + 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Cx4::readl(uint16 addr) {
|
||||||
|
return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cx4::reset() {
|
||||||
|
memset(ram, 0, 0x0c00);
|
||||||
|
memset(reg, 0, 0x0100);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,95 @@
|
||||||
|
class Cx4 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x0c00];
|
||||||
|
uint8 reg[0x0100];
|
||||||
|
uint32 r0, r1, r2, r3, r4, r5, r6, r7,
|
||||||
|
r8, r9, r10, r11, r12, r13, r14, r15;
|
||||||
|
|
||||||
|
static const uint8 immediate_data[48];
|
||||||
|
static const uint16 wave_data[40];
|
||||||
|
static const uint32 sin_table[256];
|
||||||
|
|
||||||
|
static const int16 SinTable[512];
|
||||||
|
static const int16 CosTable[512];
|
||||||
|
|
||||||
|
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
|
||||||
|
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
|
||||||
|
|
||||||
|
void C4TransfWireFrame();
|
||||||
|
void C4TransfWireFrame2();
|
||||||
|
void C4CalcWireFrame();
|
||||||
|
void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
|
||||||
|
void C4DrawWireFrame();
|
||||||
|
void C4DoScaleRotate(int row_padding);
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32 ldr(uint8 r);
|
||||||
|
void str(uint8 r, uint32 data);
|
||||||
|
void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
|
||||||
|
uint32 sin(uint32 rx);
|
||||||
|
uint32 cos(uint32 rx);
|
||||||
|
|
||||||
|
void transfer_data();
|
||||||
|
void immediate_reg(uint32 num);
|
||||||
|
|
||||||
|
void op00_00();
|
||||||
|
void op00_03();
|
||||||
|
void op00_05();
|
||||||
|
void op00_07();
|
||||||
|
void op00_08();
|
||||||
|
void op00_0b();
|
||||||
|
void op00_0c();
|
||||||
|
|
||||||
|
void op00();
|
||||||
|
void op01();
|
||||||
|
void op05();
|
||||||
|
void op0d();
|
||||||
|
void op10();
|
||||||
|
void op13();
|
||||||
|
void op15();
|
||||||
|
void op1f();
|
||||||
|
void op22();
|
||||||
|
void op25();
|
||||||
|
void op2d();
|
||||||
|
void op40();
|
||||||
|
void op54();
|
||||||
|
void op5c();
|
||||||
|
void op5e();
|
||||||
|
void op60();
|
||||||
|
void op62();
|
||||||
|
void op64();
|
||||||
|
void op66();
|
||||||
|
void op68();
|
||||||
|
void op6a();
|
||||||
|
void op6c();
|
||||||
|
void op6e();
|
||||||
|
void op70();
|
||||||
|
void op72();
|
||||||
|
void op74();
|
||||||
|
void op76();
|
||||||
|
void op78();
|
||||||
|
void op7a();
|
||||||
|
void op7c();
|
||||||
|
void op89();
|
||||||
|
|
||||||
|
uint8 readb(uint16 addr);
|
||||||
|
uint16 readw(uint16 addr);
|
||||||
|
uint32 readl(uint16 addr);
|
||||||
|
|
||||||
|
void writeb(uint16 addr, uint8 data);
|
||||||
|
void writew(uint16 addr, uint16 data);
|
||||||
|
void writel(uint16 addr, uint32 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Cx4 cx4;
|
|
@ -0,0 +1,187 @@
|
||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
const uint8 Cx4::immediate_data[48] = {
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
|
||||||
|
0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16 Cx4::wave_data[40] = {
|
||||||
|
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
|
||||||
|
0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
|
||||||
|
0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
|
||||||
|
0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
|
||||||
|
0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32 Cx4::sin_table[256] = {
|
||||||
|
0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
|
||||||
|
0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
|
||||||
|
0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
|
||||||
|
0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
|
||||||
|
0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
|
||||||
|
0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
|
||||||
|
0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
|
||||||
|
0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
|
||||||
|
0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
|
||||||
|
0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
|
||||||
|
0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
|
||||||
|
0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
|
||||||
|
0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
|
||||||
|
0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
|
||||||
|
0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
|
||||||
|
0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
|
||||||
|
0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
|
||||||
|
0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
|
||||||
|
0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
|
||||||
|
0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
|
||||||
|
0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
|
||||||
|
0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
|
||||||
|
0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
|
||||||
|
0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
|
||||||
|
0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
|
||||||
|
0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
|
||||||
|
0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
|
||||||
|
0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
|
||||||
|
0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
|
||||||
|
0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
|
||||||
|
0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
|
||||||
|
0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 Cx4::SinTable[512] = {
|
||||||
|
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||||
|
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||||
|
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||||
|
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||||
|
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||||
|
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||||
|
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||||
|
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||||
|
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||||
|
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||||
|
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||||
|
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||||
|
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||||
|
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||||
|
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||||
|
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
|
||||||
|
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||||
|
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||||
|
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||||
|
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||||
|
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||||
|
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||||
|
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||||
|
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||||
|
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||||
|
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||||
|
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||||
|
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||||
|
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||||
|
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||||
|
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||||
|
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||||
|
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||||
|
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||||
|
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||||
|
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||||
|
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||||
|
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||||
|
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||||
|
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||||
|
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||||
|
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||||
|
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||||
|
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||||
|
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||||
|
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||||
|
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||||
|
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||||
|
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||||
|
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||||
|
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||||
|
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||||
|
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||||
|
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||||
|
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||||
|
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||||
|
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||||
|
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||||
|
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||||
|
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||||
|
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||||
|
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||||
|
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||||
|
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 Cx4::CosTable[512] = {
|
||||||
|
32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
|
||||||
|
32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
|
||||||
|
32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
|
||||||
|
31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
|
||||||
|
30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
|
||||||
|
28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
|
||||||
|
27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
|
||||||
|
25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
|
||||||
|
23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
|
||||||
|
20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
|
||||||
|
18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
|
||||||
|
15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
|
||||||
|
12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
|
||||||
|
9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
|
||||||
|
6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
|
||||||
|
3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
|
||||||
|
0, -402, -804, -1206, -1607, -2009, -2410, -2811,
|
||||||
|
-3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
|
||||||
|
-6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
|
||||||
|
-9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
|
||||||
|
-12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
|
||||||
|
-15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
|
||||||
|
-18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
|
||||||
|
-20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
|
||||||
|
-23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
|
||||||
|
-25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
|
||||||
|
-27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
|
||||||
|
-28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
|
||||||
|
-30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
|
||||||
|
-31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
|
||||||
|
-32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
|
||||||
|
-32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
|
||||||
|
-32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
|
||||||
|
-32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
|
||||||
|
-32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
|
||||||
|
-31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
|
||||||
|
-30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
|
||||||
|
-28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
|
||||||
|
-27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
|
||||||
|
-25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
|
||||||
|
-23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
|
||||||
|
-20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
|
||||||
|
-18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
|
||||||
|
-15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
|
||||||
|
-12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
|
||||||
|
-9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
|
||||||
|
-6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
|
||||||
|
-3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
|
||||||
|
0, 402, 804, 1206, 1607, 2009, 2410, 2811,
|
||||||
|
3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
|
||||||
|
6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
|
||||||
|
9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
|
||||||
|
12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
|
||||||
|
15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
|
||||||
|
18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
|
||||||
|
20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
|
||||||
|
23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
|
||||||
|
25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
|
||||||
|
27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
|
||||||
|
28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
|
||||||
|
30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
|
||||||
|
31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
|
||||||
|
32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
|
||||||
|
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,251 @@
|
||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
|
||||||
|
#define sar(b, n) ((b) >> (n))
|
||||||
|
#ifdef PI
|
||||||
|
#undef PI
|
||||||
|
#endif
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
|
||||||
|
//Wireframe Helpers
|
||||||
|
void Cx4::C4TransfWireFrame() {
|
||||||
|
double c4x = (double)C4WFXVal;
|
||||||
|
double c4y = (double)C4WFYVal;
|
||||||
|
double c4z = (double)C4WFZVal - 0x95;
|
||||||
|
double tanval, c4x2, c4y2, c4z2;
|
||||||
|
|
||||||
|
//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() {
|
||||||
|
double c4x = (double)C4WFXVal;
|
||||||
|
double c4y = (double)C4WFYVal;
|
||||||
|
double c4z = (double)C4WFZVal;
|
||||||
|
double tanval, c4x2, c4y2, c4z2;
|
||||||
|
|
||||||
|
//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
|
|
@ -0,0 +1,228 @@
|
||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
//Build OAM
|
||||||
|
void Cx4::op00_00() {
|
||||||
|
uint32 oamptr = ram[0x626] << 2;
|
||||||
|
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
|
||||||
|
//clear oam-to-be
|
||||||
|
if(i >= 0) ram[i] = 0xe0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 globalx, globaly;
|
||||||
|
uint32 oamptr2;
|
||||||
|
int16 sprx, spry;
|
||||||
|
uint8 sprname, sprattr;
|
||||||
|
uint8 sprcount;
|
||||||
|
|
||||||
|
globalx = readw(0x621);
|
||||||
|
globaly = readw(0x623);
|
||||||
|
oamptr2 = 0x200 + (ram[0x626] >> 2);
|
||||||
|
|
||||||
|
if(!ram[0x620]) return;
|
||||||
|
|
||||||
|
sprcount = 128 - ram[0x626];
|
||||||
|
uint8 offset = (ram[0x626] & 3) * 2;
|
||||||
|
uint32 srcptr = 0x220;
|
||||||
|
|
||||||
|
for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
|
||||||
|
sprx = readw(srcptr) - globalx;
|
||||||
|
spry = readw(srcptr + 2) - globaly;
|
||||||
|
sprname = ram[srcptr + 5];
|
||||||
|
sprattr = ram[srcptr + 4] | ram[srcptr + 6];
|
||||||
|
|
||||||
|
uint32 spraddr = readl(srcptr + 7);
|
||||||
|
if(bus.read(spraddr)) {
|
||||||
|
int16 x, y;
|
||||||
|
for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
|
||||||
|
x = (int8)bus.read(spraddr + 1);
|
||||||
|
if(sprattr & 0x40) {
|
||||||
|
x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
|
||||||
|
}
|
||||||
|
x += sprx;
|
||||||
|
if(x >= -16 && x <= 272) {
|
||||||
|
y = (int8)bus.read(spraddr + 2);
|
||||||
|
if(sprattr & 0x80) {
|
||||||
|
y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
|
||||||
|
}
|
||||||
|
y += spry;
|
||||||
|
if(y >= -16 && y <= 224) {
|
||||||
|
ram[oamptr ] = (uint8)x;
|
||||||
|
ram[oamptr + 1] = (uint8)y;
|
||||||
|
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
|
||||||
|
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
|
||||||
|
ram[oamptr2] &= ~(3 << offset);
|
||||||
|
if(x & 0x100) ram[oamptr2] |= 1 << offset;
|
||||||
|
if(bus.read(spraddr) & 0x20) ram[oamptr2] |= 2 << offset;
|
||||||
|
oamptr += 4;
|
||||||
|
sprcount--;
|
||||||
|
offset = (offset + 2) & 6;
|
||||||
|
if(!offset)oamptr2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(sprcount > 0) {
|
||||||
|
ram[oamptr ] = (uint8)sprx;
|
||||||
|
ram[oamptr + 1] = (uint8)spry;
|
||||||
|
ram[oamptr + 2] = sprname;
|
||||||
|
ram[oamptr + 3] = sprattr;
|
||||||
|
ram[oamptr2] &= ~(3 << offset);
|
||||||
|
if(sprx & 0x100) ram[oamptr2] |= 3 << offset;
|
||||||
|
else ram[oamptr2] |= 2 << offset;
|
||||||
|
oamptr += 4;
|
||||||
|
sprcount--;
|
||||||
|
offset = (offset + 2) & 6;
|
||||||
|
if(!offset) oamptr2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Scale and Rotate
|
||||||
|
void Cx4::op00_03() {
|
||||||
|
C4DoScaleRotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Transform Lines
|
||||||
|
void Cx4::op00_05() {
|
||||||
|
C4WFX2Val = read(0x1f83);
|
||||||
|
C4WFY2Val = read(0x1f86);
|
||||||
|
C4WFDist = read(0x1f89);
|
||||||
|
C4WFScale = read(0x1f8c);
|
||||||
|
|
||||||
|
//Transform Vertices
|
||||||
|
uint32 ptr = 0;
|
||||||
|
for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
|
||||||
|
C4WFXVal = readw(ptr + 1);
|
||||||
|
C4WFYVal = readw(ptr + 5);
|
||||||
|
C4WFZVal = readw(ptr + 9);
|
||||||
|
C4TransfWireFrame();
|
||||||
|
|
||||||
|
//Displace
|
||||||
|
writew(ptr + 1, C4WFXVal + 0x80);
|
||||||
|
writew(ptr + 5, C4WFYVal + 0x50);
|
||||||
|
}
|
||||||
|
|
||||||
|
writew(0x600, 23);
|
||||||
|
writew(0x602, 0x60);
|
||||||
|
writew(0x605, 0x40);
|
||||||
|
writew(0x600 + 8, 23);
|
||||||
|
writew(0x602 + 8, 0x60);
|
||||||
|
writew(0x605 + 8, 0x40);
|
||||||
|
|
||||||
|
ptr = 0xb02;
|
||||||
|
uint32 ptr2 = 0;
|
||||||
|
|
||||||
|
for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
|
||||||
|
C4WFXVal = readw((read(ptr + 0) << 4) + 1);
|
||||||
|
C4WFYVal = readw((read(ptr + 0) << 4) + 5);
|
||||||
|
C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
|
||||||
|
C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
|
||||||
|
C4CalcWireFrame();
|
||||||
|
writew(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
|
||||||
|
writew(ptr2 + 0x602, C4WFXVal);
|
||||||
|
writew(ptr2 + 0x605, C4WFYVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Scale and Rotate
|
||||||
|
void Cx4::op00_07() {
|
||||||
|
C4DoScaleRotate(64);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw Wireframe
|
||||||
|
void Cx4::op00_08() {
|
||||||
|
C4DrawWireFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Disintegrate
|
||||||
|
void Cx4::op00_0b() {
|
||||||
|
uint8 width, height;
|
||||||
|
uint32 startx, starty;
|
||||||
|
uint32 srcptr;
|
||||||
|
uint32 x, y;
|
||||||
|
int32 scalex, scaley;
|
||||||
|
int32 cx, cy;
|
||||||
|
int32 i, j;
|
||||||
|
|
||||||
|
width = read(0x1f89);
|
||||||
|
height = read(0x1f8c);
|
||||||
|
cx = readw(0x1f80);
|
||||||
|
cy = readw(0x1f83);
|
||||||
|
|
||||||
|
scalex = (int16)readw(0x1f86);
|
||||||
|
scaley = (int16)readw(0x1f8f);
|
||||||
|
startx = -cx * scalex + (cx << 8);
|
||||||
|
starty = -cy * scaley + (cy << 8);
|
||||||
|
srcptr = 0x600;
|
||||||
|
|
||||||
|
for(i = 0; i < (width * height) >> 1; i++) {
|
||||||
|
write(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = starty, i = 0;i < height; i++, y += scaley) {
|
||||||
|
for(x = startx, j = 0;j < width; j++, x += scalex) {
|
||||||
|
if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
|
||||||
|
uint8 pixel = (j & 1) ? (ram[srcptr] >> 4) : (ram[srcptr]);
|
||||||
|
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
|
||||||
|
uint8 mask = 0x80 >> ((x >> 8) & 7);
|
||||||
|
|
||||||
|
if(pixel & 1) ram[index ] |= mask;
|
||||||
|
if(pixel & 2) ram[index + 1] |= mask;
|
||||||
|
if(pixel & 4) ram[index + 16] |= mask;
|
||||||
|
if(pixel & 8) ram[index + 17] |= mask;
|
||||||
|
}
|
||||||
|
if(j & 1) srcptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bitplane Wave
|
||||||
|
void Cx4::op00_0c() {
|
||||||
|
uint32 destptr = 0;
|
||||||
|
uint32 waveptr = read(0x1f83);
|
||||||
|
uint16 mask1 = 0xc0c0;
|
||||||
|
uint16 mask2 = 0x3f3f;
|
||||||
|
|
||||||
|
for(int j = 0; j < 0x10; j++) {
|
||||||
|
do {
|
||||||
|
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||||
|
for(int i = 0; i < 40; i++) {
|
||||||
|
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||||
|
if(height >= 0) {
|
||||||
|
if(height < 8) {
|
||||||
|
temp |= mask1 & readw(0xa00 + height * 2);
|
||||||
|
} else {
|
||||||
|
temp |= mask1 & 0xff00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writew(destptr + wave_data[i], temp);
|
||||||
|
height++;
|
||||||
|
}
|
||||||
|
waveptr = (waveptr + 1) & 0x7f;
|
||||||
|
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||||
|
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||||
|
} while(mask1 != 0xc0c0);
|
||||||
|
destptr += 16;
|
||||||
|
|
||||||
|
do {
|
||||||
|
int16 height = -((int8)read(waveptr + 0xb00)) - 16;
|
||||||
|
for(int i = 0; i < 40; i++) {
|
||||||
|
uint16 temp = readw(destptr + wave_data[i]) & mask2;
|
||||||
|
if(height >= 0) {
|
||||||
|
if(height < 8) {
|
||||||
|
temp |= mask1 & readw(0xa10 + height * 2);
|
||||||
|
} else {
|
||||||
|
temp |= mask1 & 0xff00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writew(destptr + wave_data[i], temp);
|
||||||
|
height++;
|
||||||
|
}
|
||||||
|
waveptr = (waveptr + 1) & 0x7f;
|
||||||
|
mask1 = (mask1 >> 2) | (mask1 << 6);
|
||||||
|
mask2 = (mask2 >> 2) | (mask2 << 6);
|
||||||
|
} while(mask1 != 0xc0c0);
|
||||||
|
destptr += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,227 @@
|
||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
//Sprite Functions
|
||||||
|
void Cx4::op00() {
|
||||||
|
switch(reg[0x4d]) {
|
||||||
|
case 0x00: op00_00(); break;
|
||||||
|
case 0x03: op00_03(); break;
|
||||||
|
case 0x05: op00_05(); break;
|
||||||
|
case 0x07: op00_07(); break;
|
||||||
|
case 0x08: op00_08(); break;
|
||||||
|
case 0x0b: op00_0b(); break;
|
||||||
|
case 0x0c: op00_0c(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw Wireframe
|
||||||
|
void Cx4::op01() {
|
||||||
|
memset(ram + 0x300, 0, 2304);
|
||||||
|
C4DrawWireFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Propulsion
|
||||||
|
void Cx4::op05() {
|
||||||
|
int32 temp = 0x10000;
|
||||||
|
if(readw(0x1f83)) {
|
||||||
|
temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
|
||||||
|
}
|
||||||
|
writew(0x1f80, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Vector length
|
||||||
|
void Cx4::op0d() {
|
||||||
|
C41FXVal = readw(0x1f80);
|
||||||
|
C41FYVal = readw(0x1f83);
|
||||||
|
C41FDistVal = readw(0x1f86);
|
||||||
|
double 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 {
|
||||||
|
double 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
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifdef CX4_CPP
|
||||||
|
|
||||||
|
void Cx4::serialize(serializer &s) {
|
||||||
|
s.array(ram);
|
||||||
|
s.array(reg);
|
||||||
|
|
||||||
|
s.integer(r0);
|
||||||
|
s.integer(r1);
|
||||||
|
s.integer(r2);
|
||||||
|
s.integer(r3);
|
||||||
|
s.integer(r4);
|
||||||
|
s.integer(r5);
|
||||||
|
s.integer(r6);
|
||||||
|
s.integer(r7);
|
||||||
|
s.integer(r8);
|
||||||
|
s.integer(r9);
|
||||||
|
s.integer(r10);
|
||||||
|
s.integer(r11);
|
||||||
|
s.integer(r12);
|
||||||
|
s.integer(r13);
|
||||||
|
s.integer(r14);
|
||||||
|
s.integer(r15);
|
||||||
|
|
||||||
|
s.integer(C4WFXVal);
|
||||||
|
s.integer(C4WFYVal);
|
||||||
|
s.integer(C4WFZVal);
|
||||||
|
s.integer(C4WFX2Val);
|
||||||
|
s.integer(C4WFY2Val);
|
||||||
|
s.integer(C4WFDist);
|
||||||
|
s.integer(C4WFScale);
|
||||||
|
|
||||||
|
s.integer(C41FXVal);
|
||||||
|
s.integer(C41FYVal);
|
||||||
|
s.integer(C41FAngleRes);
|
||||||
|
s.integer(C41FDist);
|
||||||
|
s.integer(C41FDistVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define DSP1_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
DSP1 dsp1;
|
||||||
|
DSP1DR dsp1dr;
|
||||||
|
DSP1SR dsp1sr;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#include "dsp1emu.cpp"
|
||||||
|
|
||||||
|
void DSP1::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP1::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP1::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP1::reset() {
|
||||||
|
dsp1.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP1DR::read(unsigned addr) { return dsp1.dsp1.getDr(); }
|
||||||
|
void DSP1DR::write(unsigned addr, uint8 data) { dsp1.dsp1.setDr(data); }
|
||||||
|
|
||||||
|
uint8 DSP1SR::read(unsigned addr) { return dsp1.dsp1.getSr(); }
|
||||||
|
void DSP1SR::write(unsigned addr, uint8 data) {}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include "dsp1emu.hpp"
|
||||||
|
|
||||||
|
class DSP1 {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Dsp1 dsp1;
|
||||||
|
friend class DSP1DR;
|
||||||
|
friend class DSP1SR;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DSP1DR : public Memory {
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DSP1SR : public Memory {
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP1 dsp1;
|
||||||
|
extern DSP1DR dsp1dr;
|
||||||
|
extern DSP1SR dsp1sr;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
||||||
|
// DSP-1's emulation code
|
||||||
|
//
|
||||||
|
// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
|
||||||
|
// Date: June 2006
|
||||||
|
|
||||||
|
#ifndef __DSP1EMUL_H
|
||||||
|
#define __DSP1EMUL_H
|
||||||
|
|
||||||
|
#define DSP1_VERSION 0x0102
|
||||||
|
|
||||||
|
class Dsp1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// The DSP-1 status register has 16 bits, but only
|
||||||
|
// the upper 8 bits can be accessed from an external device, so all these
|
||||||
|
// positions are referred to the upper byte (bits D8 to D15)
|
||||||
|
enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
|
||||||
|
|
||||||
|
// According to Overload's docs, these are the meanings of the flags:
|
||||||
|
// DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
|
||||||
|
// 0: Data transfer to and from the DSP-1 is 16 bits.
|
||||||
|
// 1: Data transfer to and from the DSP-1 is 8 bits.
|
||||||
|
// DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
|
||||||
|
// 0: Data transfer has terminated.
|
||||||
|
// 1: Data transfer in progress.
|
||||||
|
// RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
|
||||||
|
// 0: Internal Data Register Transfer.
|
||||||
|
// 1: External Data Register Transfer.
|
||||||
|
|
||||||
|
Dsp1();
|
||||||
|
uint8 getSr(); // return the status register's high byte
|
||||||
|
uint8 getDr();
|
||||||
|
void setDr(uint8 iDr);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
|
||||||
|
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
void (Dsp1::*callback)(int16 *, int16 *);
|
||||||
|
unsigned int reads;
|
||||||
|
unsigned int writes;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Command mCommandTable[];
|
||||||
|
static const int16 MaxAZS_Exp[16];
|
||||||
|
static const int16 SinTable[];
|
||||||
|
static const int16 MulTable[];
|
||||||
|
static const uint16 DataRom[];
|
||||||
|
|
||||||
|
struct SharedData { // some RAM variables shared between commands
|
||||||
|
int16 MatrixA[3][3]; // attitude matrix A
|
||||||
|
int16 MatrixB[3][3];
|
||||||
|
int16 MatrixC[3][3];
|
||||||
|
int16 CentreX, CentreY, CentreZ; // center of projection
|
||||||
|
int16 CentreZ_C, CentreZ_E;
|
||||||
|
int16 VOffset; // vertical offset of the screen with regard to the centre of projection
|
||||||
|
int16 Les, C_Les, E_Les;
|
||||||
|
int16 SinAas, CosAas;
|
||||||
|
int16 SinAzs, CosAzs;
|
||||||
|
int16 SinAZS, CosAZS;
|
||||||
|
int16 SecAZS_C1, SecAZS_E1;
|
||||||
|
int16 SecAZS_C2, SecAZS_E2;
|
||||||
|
int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
|
||||||
|
int16 Gx, Gy, Gz; // center of the screen (global coordinates)
|
||||||
|
int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
|
||||||
|
int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
|
||||||
|
|
||||||
|
} shared;
|
||||||
|
|
||||||
|
uint8 mSr; // status register
|
||||||
|
int mSrLowByteAccess;
|
||||||
|
uint16 mDr; // "internal" representation of the data register
|
||||||
|
unsigned mFsmMajorState; // current major state of the FSM
|
||||||
|
uint8 mCommand; // current command processed by the FSM
|
||||||
|
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
|
||||||
|
int16 mReadBuffer[MAX_READS];
|
||||||
|
int16 mWriteBuffer[MAX_WRITES];
|
||||||
|
bool mFreeze; // need explanation? ;)
|
||||||
|
|
||||||
|
void fsmStep(bool read, uint8 &data); // FSM logic
|
||||||
|
|
||||||
|
// commands
|
||||||
|
void memoryTest(int16 *input, int16 *output);
|
||||||
|
void memoryDump(int16 *input, int16 *output);
|
||||||
|
void memorySize(int16 *input, int16 *output);
|
||||||
|
void multiply(int16* input, int16* output);
|
||||||
|
void multiply2(int16* input, int16* output);
|
||||||
|
void inverse(int16 *input, int16 *output);
|
||||||
|
void triangle(int16 *input, int16 *output);
|
||||||
|
void radius(int16 *input, int16 *output);
|
||||||
|
void range(int16 *input, int16 *output);
|
||||||
|
void range2(int16 *input, int16 *output);
|
||||||
|
void distance(int16 *input, int16 *output);
|
||||||
|
void rotate(int16 *input, int16 *output);
|
||||||
|
void polar(int16 *input, int16 *output);
|
||||||
|
void attitudeA(int16 *input, int16 *output);
|
||||||
|
void attitudeB(int16 *input, int16 *output);
|
||||||
|
void attitudeC(int16 *input, int16 *output);
|
||||||
|
void objectiveA(int16 *input, int16 *output);
|
||||||
|
void objectiveB(int16 *input, int16 *output);
|
||||||
|
void objectiveC(int16 *input, int16 *output);
|
||||||
|
void subjectiveA(int16 *input, int16 *output);
|
||||||
|
void subjectiveB(int16 *input, int16 *output);
|
||||||
|
void subjectiveC(int16 *input, int16 *output);
|
||||||
|
void scalarA(int16 *input, int16 *output);
|
||||||
|
void scalarB(int16 *input, int16 *output);
|
||||||
|
void scalarC(int16 *input, int16 *output);
|
||||||
|
void gyrate(int16 *input, int16 *output);
|
||||||
|
void parameter(int16 *input, int16 *output);
|
||||||
|
void raster(int16 *input, int16 *output);
|
||||||
|
void target(int16 *input, int16 *output);
|
||||||
|
void project(int16 *input, int16 *output);
|
||||||
|
|
||||||
|
// auxiliar functions
|
||||||
|
int16 sin(int16 Angle);
|
||||||
|
int16 cos(int16 Angle);
|
||||||
|
void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
|
||||||
|
int16 denormalizeAndClip(int16 C, int16 E);
|
||||||
|
void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
|
||||||
|
void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
|
||||||
|
int16 shiftR(int16 C, int16 E);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifdef DSP1_CPP
|
||||||
|
|
||||||
|
void DSP1::serialize(serializer &s) {
|
||||||
|
dsp1.serialize(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dsp1::serialize(serializer &s) {
|
||||||
|
for(unsigned i = 0; i < 3; i++) {
|
||||||
|
s.array(shared.MatrixA[i]);
|
||||||
|
s.array(shared.MatrixB[i]);
|
||||||
|
s.array(shared.MatrixC[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.integer(shared.CentreX);
|
||||||
|
s.integer(shared.CentreY);
|
||||||
|
s.integer(shared.CentreZ);
|
||||||
|
s.integer(shared.CentreZ_C);
|
||||||
|
s.integer(shared.CentreZ_E);
|
||||||
|
s.integer(shared.VOffset);
|
||||||
|
s.integer(shared.Les);
|
||||||
|
s.integer(shared.C_Les);
|
||||||
|
s.integer(shared.E_Les);
|
||||||
|
s.integer(shared.SinAas);
|
||||||
|
s.integer(shared.CosAas);
|
||||||
|
s.integer(shared.SinAzs);
|
||||||
|
s.integer(shared.CosAzs);
|
||||||
|
s.integer(shared.SinAZS);
|
||||||
|
s.integer(shared.CosAZS);
|
||||||
|
s.integer(shared.SecAZS_C1);
|
||||||
|
s.integer(shared.SecAZS_E1);
|
||||||
|
s.integer(shared.SecAZS_C2);
|
||||||
|
s.integer(shared.SecAZS_E2);
|
||||||
|
s.integer(shared.Nx);
|
||||||
|
s.integer(shared.Ny);
|
||||||
|
s.integer(shared.Nz);
|
||||||
|
s.integer(shared.Gx);
|
||||||
|
s.integer(shared.Gy);
|
||||||
|
s.integer(shared.Gz);
|
||||||
|
s.integer(shared.Hx);
|
||||||
|
s.integer(shared.Hy);
|
||||||
|
s.integer(shared.Vx);
|
||||||
|
s.integer(shared.Vy);
|
||||||
|
s.integer(shared.Vz);
|
||||||
|
|
||||||
|
s.integer(mSr);
|
||||||
|
s.integer(mSrLowByteAccess);
|
||||||
|
s.integer(mDr);
|
||||||
|
s.integer(mFsmMajorState);
|
||||||
|
s.integer(mCommand);
|
||||||
|
s.integer(mDataCounter);
|
||||||
|
s.array(mReadBuffer);
|
||||||
|
s.array(mWriteBuffer);
|
||||||
|
s.integer(mFreeze);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define DSP2_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
DSP2 dsp2;
|
||||||
|
DSP2DR dsp2dr;
|
||||||
|
DSP2SR dsp2sr;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#include "opcodes.cpp"
|
||||||
|
|
||||||
|
void DSP2::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::reset() {
|
||||||
|
status.waiting_for_command = true;
|
||||||
|
status.in_count = 0;
|
||||||
|
status.in_index = 0;
|
||||||
|
status.out_count = 0;
|
||||||
|
status.out_index = 0;
|
||||||
|
|
||||||
|
status.op05transparent = 0;
|
||||||
|
status.op05haslen = false;
|
||||||
|
status.op05len = 0;
|
||||||
|
status.op06haslen = false;
|
||||||
|
status.op06len = 0;
|
||||||
|
status.op09word1 = 0;
|
||||||
|
status.op09word2 = 0;
|
||||||
|
status.op0dhaslen = false;
|
||||||
|
status.op0doutlen = 0;
|
||||||
|
status.op0dinlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP2::read(unsigned addr) {
|
||||||
|
uint8 r = 0xff;
|
||||||
|
if(status.out_count) {
|
||||||
|
r = status.output[status.out_index++];
|
||||||
|
status.out_index &= 511;
|
||||||
|
if(status.out_count == status.out_index) {
|
||||||
|
status.out_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP2::write(unsigned addr, uint8 data) {
|
||||||
|
if(status.waiting_for_command) {
|
||||||
|
status.command = data;
|
||||||
|
status.in_index = 0;
|
||||||
|
status.waiting_for_command = false;
|
||||||
|
|
||||||
|
switch(data) {
|
||||||
|
case 0x01: status.in_count = 32; break;
|
||||||
|
case 0x03: status.in_count = 1; break;
|
||||||
|
case 0x05: status.in_count = 1; break;
|
||||||
|
case 0x06: status.in_count = 1; break;
|
||||||
|
case 0x07: break;
|
||||||
|
case 0x08: break;
|
||||||
|
case 0x09: status.in_count = 4; break;
|
||||||
|
case 0x0d: status.in_count = 2; break;
|
||||||
|
case 0x0f: status.in_count = 0; break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status.parameters[status.in_index++] = data;
|
||||||
|
status.in_index &= 511;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.in_count == status.in_index) {
|
||||||
|
status.waiting_for_command = true;
|
||||||
|
status.out_index = 0;
|
||||||
|
switch(status.command) {
|
||||||
|
case 0x01: {
|
||||||
|
status.out_count = 32;
|
||||||
|
op01();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x03: {
|
||||||
|
op03();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x05: {
|
||||||
|
if(status.op05haslen) {
|
||||||
|
status.op05haslen = false;
|
||||||
|
status.out_count = status.op05len;
|
||||||
|
op05();
|
||||||
|
} else {
|
||||||
|
status.op05len = status.parameters[0];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = status.op05len * 2;
|
||||||
|
status.op05haslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x06: {
|
||||||
|
if(status.op06haslen) {
|
||||||
|
status.op06haslen = false;
|
||||||
|
status.out_count = status.op06len;
|
||||||
|
op06();
|
||||||
|
} else {
|
||||||
|
status.op06len = status.parameters[0];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = status.op06len;
|
||||||
|
status.op06haslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x07: break;
|
||||||
|
case 0x08: break;
|
||||||
|
|
||||||
|
case 0x09: {
|
||||||
|
op09();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x0d: {
|
||||||
|
if(status.op0dhaslen) {
|
||||||
|
status.op0dhaslen = false;
|
||||||
|
status.out_count = status.op0doutlen;
|
||||||
|
op0d();
|
||||||
|
} else {
|
||||||
|
status.op0dinlen = status.parameters[0];
|
||||||
|
status.op0doutlen = status.parameters[1];
|
||||||
|
status.in_index = 0;
|
||||||
|
status.in_count = (status.op0dinlen + 1) >> 1;
|
||||||
|
status.op0dhaslen = true;
|
||||||
|
if(data)status.waiting_for_command = false;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x0f: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DSP2::DSP2() {}
|
||||||
|
DSP2::~DSP2() {}
|
||||||
|
|
||||||
|
uint8 DSP2DR::read(unsigned addr) { return dsp2.read(addr); }
|
||||||
|
void DSP2DR::write(unsigned addr, uint8 data) { dsp2.write(addr, data); }
|
||||||
|
|
||||||
|
uint8 DSP2SR::read(unsigned addr) { return 0x00; }
|
||||||
|
void DSP2SR::write(unsigned addr, uint8 data) {}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
class DSP2 {
|
||||||
|
public:
|
||||||
|
struct {
|
||||||
|
bool waiting_for_command;
|
||||||
|
unsigned command;
|
||||||
|
unsigned in_count, in_index;
|
||||||
|
unsigned out_count, out_index;
|
||||||
|
|
||||||
|
uint8 parameters[512];
|
||||||
|
uint8 output[512];
|
||||||
|
|
||||||
|
uint8 op05transparent;
|
||||||
|
bool op05haslen;
|
||||||
|
int op05len;
|
||||||
|
bool op06haslen;
|
||||||
|
int op06len;
|
||||||
|
uint16 op09word1;
|
||||||
|
uint16 op09word2;
|
||||||
|
bool op0dhaslen;
|
||||||
|
int op0doutlen;
|
||||||
|
int op0dinlen;
|
||||||
|
} status;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
DSP2();
|
||||||
|
~DSP2();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void op01();
|
||||||
|
void op03();
|
||||||
|
void op05();
|
||||||
|
void op06();
|
||||||
|
void op09();
|
||||||
|
void op0d();
|
||||||
|
};
|
||||||
|
|
||||||
|
class DSP2DR : public Memory {
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DSP2SR : public Memory {
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP2 dsp2;
|
||||||
|
extern DSP2DR dsp2dr;
|
||||||
|
extern DSP2SR dsp2sr;
|
|
@ -0,0 +1,177 @@
|
||||||
|
#ifdef DSP2_CPP
|
||||||
|
|
||||||
|
//convert bitmap to bitplane tile
|
||||||
|
void DSP2::op01() {
|
||||||
|
//op01 size is always 32 bytes input and output
|
||||||
|
//the hardware does strange things if you vary the size
|
||||||
|
|
||||||
|
unsigned char c0, c1, c2, c3;
|
||||||
|
unsigned char *p1 = status.parameters;
|
||||||
|
unsigned char *p2a = status.output;
|
||||||
|
unsigned char *p2b = status.output + 16; //halfway
|
||||||
|
|
||||||
|
//process 8 blocks of 4 bytes each
|
||||||
|
for(int j = 0; j < 8; j++) {
|
||||||
|
c0 = *p1++;
|
||||||
|
c1 = *p1++;
|
||||||
|
c2 = *p1++;
|
||||||
|
c3 = *p1++;
|
||||||
|
|
||||||
|
*p2a++ = (c0 & 0x10) << 3 |
|
||||||
|
(c0 & 0x01) << 6 |
|
||||||
|
(c1 & 0x10) << 1 |
|
||||||
|
(c1 & 0x01) << 4 |
|
||||||
|
(c2 & 0x10) >> 1 |
|
||||||
|
(c2 & 0x01) << 2 |
|
||||||
|
(c3 & 0x10) >> 3 |
|
||||||
|
(c3 & 0x01);
|
||||||
|
|
||||||
|
*p2a++ = (c0 & 0x20) << 2 |
|
||||||
|
(c0 & 0x02) << 5 |
|
||||||
|
(c1 & 0x20) |
|
||||||
|
(c1 & 0x02) << 3 |
|
||||||
|
(c2 & 0x20) >> 2 |
|
||||||
|
(c2 & 0x02) << 1 |
|
||||||
|
(c3 & 0x20) >> 4 |
|
||||||
|
(c3 & 0x02) >> 1;
|
||||||
|
|
||||||
|
*p2b++ = (c0 & 0x40) << 1 |
|
||||||
|
(c0 & 0x04) << 4 |
|
||||||
|
(c1 & 0x40) >> 1 |
|
||||||
|
(c1 & 0x04) << 2 |
|
||||||
|
(c2 & 0x40) >> 3 |
|
||||||
|
(c2 & 0x04) |
|
||||||
|
(c3 & 0x40) >> 5 |
|
||||||
|
(c3 & 0x04) >> 2;
|
||||||
|
|
||||||
|
*p2b++ = (c0 & 0x80) |
|
||||||
|
(c0 & 0x08) << 3 |
|
||||||
|
(c1 & 0x80) >> 2 |
|
||||||
|
(c1 & 0x08) << 1 |
|
||||||
|
(c2 & 0x80) >> 4 |
|
||||||
|
(c2 & 0x08) >> 1 |
|
||||||
|
(c3 & 0x80) >> 6 |
|
||||||
|
(c3 & 0x08) >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//set transparent color
|
||||||
|
void DSP2::op03() {
|
||||||
|
status.op05transparent = status.parameters[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//replace bitmap using transparent color
|
||||||
|
void DSP2::op05() {
|
||||||
|
uint8 color;
|
||||||
|
// Overlay bitmap with transparency.
|
||||||
|
// Input:
|
||||||
|
//
|
||||||
|
// Bitmap 1: i[0] <=> i[size-1]
|
||||||
|
// Bitmap 2: i[size] <=> i[2*size-1]
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// Bitmap 3: o[0] <=> o[size-1]
|
||||||
|
//
|
||||||
|
// Processing:
|
||||||
|
//
|
||||||
|
// Process all 4-bit pixels (nibbles) in the bitmap
|
||||||
|
//
|
||||||
|
// if ( BM2_pixel == transparent_color )
|
||||||
|
// pixelout = BM1_pixel
|
||||||
|
// else
|
||||||
|
// pixelout = BM2_pixel
|
||||||
|
|
||||||
|
// The max size bitmap is limited to 255 because the size parameter is a byte
|
||||||
|
// I think size=0 is an error. The behavior of the chip on size=0 is to
|
||||||
|
// return the last value written to DR if you read DR on Op05 with
|
||||||
|
// size = 0. I don't think it's worth implementing this quirk unless it's
|
||||||
|
// proven necessary.
|
||||||
|
|
||||||
|
unsigned char c1, c2;
|
||||||
|
unsigned char *p1 = status.parameters;
|
||||||
|
unsigned char *p2 = status.parameters + status.op05len;
|
||||||
|
unsigned char *p3 = status.output;
|
||||||
|
|
||||||
|
color = status.op05transparent & 0x0f;
|
||||||
|
|
||||||
|
for(int n = 0; n < status.op05len; n++) {
|
||||||
|
c1 = *p1++;
|
||||||
|
c2 = *p2++;
|
||||||
|
*p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
|
||||||
|
( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//reverse bitmap
|
||||||
|
void DSP2::op06() {
|
||||||
|
// Input:
|
||||||
|
// size
|
||||||
|
// bitmap
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
|
||||||
|
status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiply
|
||||||
|
void DSP2::op09() {
|
||||||
|
status.out_count = 4;
|
||||||
|
|
||||||
|
status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
|
||||||
|
status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
|
||||||
|
|
||||||
|
uint32 r;
|
||||||
|
r = status.op09word1 * status.op09word2;
|
||||||
|
status.output[0] = r;
|
||||||
|
status.output[1] = r >> 8;
|
||||||
|
status.output[2] = r >> 16;
|
||||||
|
status.output[3] = r >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
//scale bitmap
|
||||||
|
void DSP2::op0d() {
|
||||||
|
// Bit accurate hardware algorithm - uses fixed point math
|
||||||
|
// This should match the DSP2 Op0D output exactly
|
||||||
|
// I wouldn't recommend using this unless you're doing hardware debug.
|
||||||
|
// In some situations it has small visual artifacts that
|
||||||
|
// are not readily apparent on a TV screen but show up clearly
|
||||||
|
// on a monitor. Use Overload's scaling instead.
|
||||||
|
// This is for hardware verification testing.
|
||||||
|
//
|
||||||
|
// One note: the HW can do odd byte scaling but since we divide
|
||||||
|
// by two to get the count of bytes this won't work well for
|
||||||
|
// odd byte scaling (in any of the current algorithm implementations).
|
||||||
|
// So far I haven't seen Dungeon Master use it.
|
||||||
|
// If it does we can adjust the parameters and code to work with it
|
||||||
|
|
||||||
|
uint32 multiplier; // Any size int >= 32-bits
|
||||||
|
uint32 pixloc; // match size of multiplier
|
||||||
|
int i, j;
|
||||||
|
uint8 pixelarray[512];
|
||||||
|
if(status.op0dinlen <= status.op0doutlen) {
|
||||||
|
multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
|
||||||
|
} else {
|
||||||
|
multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixloc = 0;
|
||||||
|
for(i = 0; i < status.op0doutlen * 2; i++) {
|
||||||
|
j = pixloc >> 16;
|
||||||
|
|
||||||
|
if(j & 1) {
|
||||||
|
pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
|
||||||
|
} else {
|
||||||
|
pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixloc += multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < status.op0doutlen; i++) {
|
||||||
|
status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifdef DSP2_CPP
|
||||||
|
|
||||||
|
void DSP2::serialize(serializer &s) {
|
||||||
|
s.integer(status.waiting_for_command);
|
||||||
|
s.integer(status.command);
|
||||||
|
s.integer(status.in_count);
|
||||||
|
s.integer(status.in_index);
|
||||||
|
s.integer(status.out_count);
|
||||||
|
s.integer(status.out_index);
|
||||||
|
|
||||||
|
s.array(status.parameters);
|
||||||
|
s.array(status.output);
|
||||||
|
|
||||||
|
s.integer(status.op05transparent);
|
||||||
|
s.integer(status.op05haslen);
|
||||||
|
s.integer(status.op05len);
|
||||||
|
s.integer(status.op06haslen);
|
||||||
|
s.integer(status.op06len);
|
||||||
|
s.integer(status.op09word1);
|
||||||
|
s.integer(status.op09word2);
|
||||||
|
s.integer(status.op0dhaslen);
|
||||||
|
s.integer(status.op0doutlen);
|
||||||
|
s.integer(status.op0dinlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define DSP3_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
DSP3 dsp3;
|
||||||
|
|
||||||
|
namespace DSP3i {
|
||||||
|
#define bool8 uint8
|
||||||
|
#include "dsp3emu.c"
|
||||||
|
#undef bool8
|
||||||
|
};
|
||||||
|
|
||||||
|
void DSP3::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::reset() {
|
||||||
|
DSP3i::DSP3_Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 DSP3::read(unsigned addr) {
|
||||||
|
DSP3i::dsp3_address = addr & 0xffff;
|
||||||
|
DSP3i::DSP3GetByte();
|
||||||
|
return DSP3i::dsp3_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP3::write(unsigned addr, uint8 data) {
|
||||||
|
DSP3i::dsp3_address = addr & 0xffff;
|
||||||
|
DSP3i::dsp3_byte = data;
|
||||||
|
DSP3i::DSP3SetByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
class DSP3 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP3 dsp3;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,60 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define DSP4_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
DSP4 dsp4;
|
||||||
|
|
||||||
|
void DSP4::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSP4::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DSP4i {
|
||||||
|
inline uint16 READ_WORD(uint8 *addr) {
|
||||||
|
return (addr[0]) + (addr[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 READ_DWORD(uint8 *addr) {
|
||||||
|
return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WRITE_WORD(uint8 *addr, uint16 data) {
|
||||||
|
addr[0] = data;
|
||||||
|
addr[1] = data >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define bool8 uint8
|
||||||
|
#include "dsp4emu.c"
|
||||||
|
#undef bool8
|
||||||
|
};
|
||||||
|
|
||||||
|
void DSP4::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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
class DSP4 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read (unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DSP4 dsp4;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,108 @@
|
||||||
|
//DSP-4 emulator code
|
||||||
|
//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
|
||||||
|
|
||||||
|
#ifndef DSP4EMU_H
|
||||||
|
#define DSP4EMU_H
|
||||||
|
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
#define TRUE true
|
||||||
|
#define FALSE false
|
||||||
|
|
||||||
|
struct DSP4_t
|
||||||
|
{
|
||||||
|
bool8 waiting4command;
|
||||||
|
bool8 half_command;
|
||||||
|
uint16 command;
|
||||||
|
uint32 in_count;
|
||||||
|
uint32 in_index;
|
||||||
|
uint32 out_count;
|
||||||
|
uint32 out_index;
|
||||||
|
uint8 parameters[512];
|
||||||
|
uint8 output[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct DSP4_t DSP4;
|
||||||
|
|
||||||
|
struct DSP4_vars_t
|
||||||
|
{
|
||||||
|
// op control
|
||||||
|
int8 DSP4_Logic; // controls op flow
|
||||||
|
|
||||||
|
|
||||||
|
// projection format
|
||||||
|
int16 lcv; // loop-control variable
|
||||||
|
int16 distance; // z-position into virtual world
|
||||||
|
int16 raster; // current raster line
|
||||||
|
int16 segments; // number of raster lines drawn
|
||||||
|
|
||||||
|
// 1.15.16 or 1.15.0 [sign, integer, fraction]
|
||||||
|
int32 world_x; // line of x-projection in world
|
||||||
|
int32 world_y; // line of y-projection in world
|
||||||
|
int32 world_dx; // projection line x-delta
|
||||||
|
int32 world_dy; // projection line y-delta
|
||||||
|
int16 world_ddx; // x-delta increment
|
||||||
|
int16 world_ddy; // y-delta increment
|
||||||
|
int32 world_xenv; // world x-shaping factor
|
||||||
|
int16 world_yofs; // world y-vertical scroll
|
||||||
|
|
||||||
|
int16 view_x1; // current viewer-x
|
||||||
|
int16 view_y1; // current viewer-y
|
||||||
|
int16 view_x2; // future viewer-x
|
||||||
|
int16 view_y2; // future viewer-y
|
||||||
|
int16 view_dx; // view x-delta factor
|
||||||
|
int16 view_dy; // view y-delta factor
|
||||||
|
int16 view_xofs1; // current viewer x-vertical scroll
|
||||||
|
int16 view_yofs1; // current viewer y-vertical scroll
|
||||||
|
int16 view_xofs2; // future viewer x-vertical scroll
|
||||||
|
int16 view_yofs2; // future viewer y-vertical scroll
|
||||||
|
int16 view_yofsenv; // y-scroll shaping factor
|
||||||
|
int16 view_turnoff_x; // road turnoff data
|
||||||
|
int16 view_turnoff_dx; // road turnoff delta factor
|
||||||
|
|
||||||
|
|
||||||
|
// drawing area
|
||||||
|
|
||||||
|
int16 viewport_cx; // x-center of viewport window
|
||||||
|
int16 viewport_cy; // y-center of render window
|
||||||
|
int16 viewport_left; // x-left of viewport
|
||||||
|
int16 viewport_right; // x-right of viewport
|
||||||
|
int16 viewport_top; // y-top of viewport
|
||||||
|
int16 viewport_bottom; // y-bottom of viewport
|
||||||
|
|
||||||
|
|
||||||
|
// sprite structure
|
||||||
|
|
||||||
|
int16 sprite_x; // projected x-pos of sprite
|
||||||
|
int16 sprite_y; // projected y-pos of sprite
|
||||||
|
int16 sprite_attr; // obj attributes
|
||||||
|
bool8 sprite_size; // sprite size: 8x8 or 16x16
|
||||||
|
int16 sprite_clipy; // visible line to clip pixels off
|
||||||
|
int16 sprite_count;
|
||||||
|
|
||||||
|
// generic projection variables designed for
|
||||||
|
// two solid polygons + two polygon sides
|
||||||
|
|
||||||
|
int16 poly_clipLf[2][2]; // left clip boundary
|
||||||
|
int16 poly_clipRt[2][2]; // right clip boundary
|
||||||
|
int16 poly_ptr[2][2]; // HDMA structure pointers
|
||||||
|
int16 poly_raster[2][2]; // current raster line below horizon
|
||||||
|
int16 poly_top[2][2]; // top clip boundary
|
||||||
|
int16 poly_bottom[2][2]; // bottom clip boundary
|
||||||
|
int16 poly_cx[2][2]; // center for left/right points
|
||||||
|
int16 poly_start[2]; // current projection points
|
||||||
|
int16 poly_plane[2]; // previous z-plane distance
|
||||||
|
|
||||||
|
|
||||||
|
// OAM
|
||||||
|
int16 OAM_attr[16]; // OAM (size,MSB) data
|
||||||
|
int16 OAM_index; // index into OAM table
|
||||||
|
int16 OAM_bits; // offset into OAM table
|
||||||
|
|
||||||
|
int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
|
||||||
|
int16 OAM_Row[32]; // current number of tiles per row
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct DSP4_vars_t DSP4_vars;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,148 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define MSU1_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
MSU1 msu1;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
void MSU1::Enter() { msu1.enter(); }
|
||||||
|
|
||||||
|
void MSU1::enter() {
|
||||||
|
while(true) {
|
||||||
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 left = 0, right = 0;
|
||||||
|
|
||||||
|
if(mmio.audio_play) {
|
||||||
|
if(audiofile.open()) {
|
||||||
|
if(audiofile.end()) {
|
||||||
|
if(!mmio.audio_repeat) mmio.audio_play = false;
|
||||||
|
audiofile.seek(mmio.audio_offset = 58);
|
||||||
|
} else {
|
||||||
|
mmio.audio_offset += 4;
|
||||||
|
left = audiofile.readl(2);
|
||||||
|
right = audiofile.readl(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mmio.audio_play = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
left = sclamp<16>((double)left * (double)mmio.audio_volume / 255.0);
|
||||||
|
right = sclamp<16>((double)right * (double)mmio.audio_volume / 255.0);
|
||||||
|
|
||||||
|
audio.coprocessor_sample(left, right);
|
||||||
|
step(1);
|
||||||
|
synchronize_cpu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSU1::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSU1::enable() {
|
||||||
|
audio.coprocessor_enable(true);
|
||||||
|
audio.coprocessor_frequency(44100.0);
|
||||||
|
|
||||||
|
if(datafile.open()) datafile.close();
|
||||||
|
datafile.open(string() << cartridge.basename() << ".msu", file::mode_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSU1::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSU1::reset() {
|
||||||
|
create(MSU1::Enter, 44100);
|
||||||
|
|
||||||
|
mmio.data_offset = 0;
|
||||||
|
mmio.audio_offset = 0;
|
||||||
|
mmio.audio_track = 0;
|
||||||
|
mmio.audio_volume = 255;
|
||||||
|
mmio.data_busy = true;
|
||||||
|
mmio.audio_busy = true;
|
||||||
|
mmio.audio_repeat = false;
|
||||||
|
mmio.audio_play = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 MSU1::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2000) {
|
||||||
|
return (mmio.data_busy << 7)
|
||||||
|
| (mmio.audio_busy << 6)
|
||||||
|
| (mmio.audio_repeat << 5)
|
||||||
|
| (mmio.audio_play << 4)
|
||||||
|
| (Revision << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2001) {
|
||||||
|
if(mmio.data_busy) return 0x00;
|
||||||
|
mmio.data_offset++;
|
||||||
|
if(datafile.open()) return datafile.read();
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2002) return 'S';
|
||||||
|
if(addr == 0x2003) return '-';
|
||||||
|
if(addr == 0x2004) return 'M';
|
||||||
|
if(addr == 0x2005) return 'S';
|
||||||
|
if(addr == 0x2006) return 'U';
|
||||||
|
if(addr == 0x2007) return '0' + Revision;
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSU1::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2000) {
|
||||||
|
mmio.data_offset = (mmio.data_offset & 0xffffff00) | (data << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2001) {
|
||||||
|
mmio.data_offset = (mmio.data_offset & 0xffff00ff) | (data << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2002) {
|
||||||
|
mmio.data_offset = (mmio.data_offset & 0xff00ffff) | (data << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2003) {
|
||||||
|
mmio.data_offset = (mmio.data_offset & 0x00ffffff) | (data << 24);
|
||||||
|
if(datafile.open()) datafile.seek(mmio.data_offset);
|
||||||
|
mmio.data_busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2004) {
|
||||||
|
mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2005) {
|
||||||
|
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
|
||||||
|
if(audiofile.open()) audiofile.close();
|
||||||
|
char track[16];
|
||||||
|
sprintf(track, "-%u", mmio.audio_track);
|
||||||
|
if(audiofile.open(string() << cartridge.basename() << track << ".wav", file::mode_read)) {
|
||||||
|
audiofile.seek(mmio.audio_offset = 58); //skip WAV header
|
||||||
|
}
|
||||||
|
mmio.audio_busy = false;
|
||||||
|
mmio.audio_repeat = false;
|
||||||
|
mmio.audio_play = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2006) {
|
||||||
|
mmio.audio_volume = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x2007) {
|
||||||
|
mmio.audio_repeat = data & 2;
|
||||||
|
mmio.audio_play = data & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
class MSU1 : public Coprocessor, public MMIO {
|
||||||
|
public:
|
||||||
|
static void Enter();
|
||||||
|
void enter();
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
file datafile;
|
||||||
|
file audiofile;
|
||||||
|
|
||||||
|
enum Flag {
|
||||||
|
DataBusy = 0x80,
|
||||||
|
AudioBusy = 0x40,
|
||||||
|
AudioRepeating = 0x20,
|
||||||
|
AudioPlaying = 0x10,
|
||||||
|
Revision = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MMIO {
|
||||||
|
uint32 data_offset;
|
||||||
|
uint32 audio_offset;
|
||||||
|
uint16 audio_track;
|
||||||
|
uint8 audio_volume;
|
||||||
|
bool data_busy;
|
||||||
|
bool audio_busy;
|
||||||
|
bool audio_repeat;
|
||||||
|
bool audio_play;
|
||||||
|
} mmio;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern MSU1 msu1;
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifdef MSU1_CPP
|
||||||
|
|
||||||
|
void MSU1::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
|
||||||
|
s.integer(mmio.data_offset);
|
||||||
|
s.integer(mmio.audio_offset);
|
||||||
|
s.integer(mmio.audio_track);
|
||||||
|
s.integer(mmio.audio_volume);
|
||||||
|
s.integer(mmio.data_busy);
|
||||||
|
s.integer(mmio.audio_busy);
|
||||||
|
s.integer(mmio.audio_repeat);
|
||||||
|
s.integer(mmio.audio_play);
|
||||||
|
|
||||||
|
if(datafile.open()) datafile.close();
|
||||||
|
if(datafile.open(string() << cartridge.basename() << ".msu", file::mode_read)) {
|
||||||
|
datafile.seek(mmio.data_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(audiofile.open()) audiofile.close();
|
||||||
|
char track[16];
|
||||||
|
sprintf(track, "-%u", mmio.audio_track);
|
||||||
|
if(audiofile.open(string() << cartridge.basename() << track << ".wav", file::mode_read)) {
|
||||||
|
audiofile.seek(mmio.audio_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define OBC1_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
OBC1 obc1;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
class OBC1 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
OBC1();
|
||||||
|
~OBC1();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram_read(unsigned addr);
|
||||||
|
void ram_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16 address;
|
||||||
|
uint16 baseptr;
|
||||||
|
uint16 shift;
|
||||||
|
} status;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern OBC1 obc1;
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifdef OBC1_CPP
|
||||||
|
|
||||||
|
void OBC1::serialize(serializer &s) {
|
||||||
|
s.integer(status.address);
|
||||||
|
s.integer(status.baseptr);
|
||||||
|
s.integer(status.shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,218 @@
|
||||||
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
|
VBRBus vbrbus;
|
||||||
|
SA1Bus sa1bus;
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
StaticRAM iram(2048);
|
||||||
|
//accessed by:
|
||||||
|
VSPROM vsprom; //S-CPU + SA-1
|
||||||
|
CPUIRAM cpuiram; //S-CPU
|
||||||
|
SA1IRAM sa1iram; //SA-1
|
||||||
|
SA1BWRAM sa1bwram; //SA-1
|
||||||
|
CC1BWRAM cc1bwram; //S-CPU
|
||||||
|
BitmapRAM bitmapram; //SA-1
|
||||||
|
}
|
||||||
|
|
||||||
|
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.
|
||||||
|
//this is used both to avoid VBR-reads from accessing MMIO registers, and
|
||||||
|
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||||
|
//these ports.
|
||||||
|
//(* eg, memory::cartram is used directly, as memory::sa1bwram syncs to the S-CPU)
|
||||||
|
void VBRBus::init() {
|
||||||
|
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||||
|
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cartram);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
|
||||||
|
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::cartram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cartram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
|
||||||
|
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1Bus::init() {
|
||||||
|
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||||
|
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::sa1iram);
|
||||||
|
map(MapMode::Direct, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1iram);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
|
||||||
|
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1bwram);
|
||||||
|
map(MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1iram);
|
||||||
|
map(MapMode::Direct, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1iram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram);
|
||||||
|
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
|
||||||
|
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
|
||||||
|
}
|
||||||
|
|
||||||
|
//======
|
||||||
|
//VSPROM
|
||||||
|
//======
|
||||||
|
|
||||||
|
//this class maps $00:[ff00-ffff] for the purpose of supporting:
|
||||||
|
//$2209.d6 IVSW (S-CPU IRQ vector selection) (0 = cart, 1 = SA-1)
|
||||||
|
//$2209.d4 NVSW (S-CPU NMI vector selection) (0 = cart, 1 = SA-1)
|
||||||
|
//when set, vector addresses are over-ridden with SA-1 register settings:
|
||||||
|
//SIV = S-CPU IRQ vector address override
|
||||||
|
//SNV = S-CPU NMI vector address override
|
||||||
|
//
|
||||||
|
//$00:[ffea-ffeb|ffee-ffef] are special cased on read;
|
||||||
|
//all other addresses return original mapped data.
|
||||||
|
|
||||||
|
unsigned VSPROM::size() const {
|
||||||
|
return memory::cartrom.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 VSPROM::read(unsigned addr) {
|
||||||
|
//use $7fex instead of $ffex due to linear mapping of 32k granularity ROM data
|
||||||
|
if((addr & 0xffffe0) == 0x007fe0) {
|
||||||
|
if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
||||||
|
if(addr == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
||||||
|
if(addr == 0x7fee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
|
||||||
|
if(addr == 0x7fef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
|
||||||
|
}
|
||||||
|
return memory::cartrom.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSPROM::write(unsigned addr, uint8 data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======
|
||||||
|
//SA1IRAM
|
||||||
|
//=======
|
||||||
|
|
||||||
|
unsigned SA1IRAM::size() const {
|
||||||
|
return memory::iram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SA1IRAM::read(unsigned addr) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
return memory::iram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1IRAM::write(unsigned addr, uint8 data) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
memory::iram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======
|
||||||
|
//CPUIRAM
|
||||||
|
//=======
|
||||||
|
|
||||||
|
unsigned CPUIRAM::size() const {
|
||||||
|
return memory::iram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 CPUIRAM::read(unsigned addr) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
return memory::iram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPUIRAM::write(unsigned addr, uint8 data) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
memory::iram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//========
|
||||||
|
//SA1BWRAM
|
||||||
|
//========
|
||||||
|
|
||||||
|
unsigned SA1BWRAM::size() const {
|
||||||
|
return memory::cartram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SA1BWRAM::read(unsigned addr) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
return memory::cartram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1BWRAM::write(unsigned addr, uint8 data) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
memory::cartram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//========
|
||||||
|
//CC1BWRAM
|
||||||
|
//========
|
||||||
|
|
||||||
|
unsigned CC1BWRAM::size() const {
|
||||||
|
return memory::cartram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 CC1BWRAM::read(unsigned addr) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
if(dma) return sa1.dma_cc1_read(addr);
|
||||||
|
return memory::cartram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CC1BWRAM::write(unsigned addr, uint8 data) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
memory::cartram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//BitmapRAM
|
||||||
|
//=========
|
||||||
|
|
||||||
|
unsigned BitmapRAM::size() const {
|
||||||
|
return 0x100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 BitmapRAM::read(unsigned addr) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
|
||||||
|
if(sa1.mmio.bbf == 0) {
|
||||||
|
//4bpp
|
||||||
|
unsigned shift = addr & 1;
|
||||||
|
addr = (addr >> 1) & (memory::cartram.size() - 1);
|
||||||
|
switch(shift) { default:
|
||||||
|
case 0: return (memory::cartram.read(addr) >> 0) & 15;
|
||||||
|
case 1: return (memory::cartram.read(addr) >> 4) & 15;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//2bpp
|
||||||
|
unsigned shift = addr & 3;
|
||||||
|
addr = (addr >> 2) & (memory::cartram.size() - 1);
|
||||||
|
switch(shift) { default:
|
||||||
|
case 0: return (memory::cartram.read(addr) >> 0) & 3;
|
||||||
|
case 1: return (memory::cartram.read(addr) >> 2) & 3;
|
||||||
|
case 2: return (memory::cartram.read(addr) >> 4) & 3;
|
||||||
|
case 3: return (memory::cartram.read(addr) >> 6) & 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitmapRAM::write(unsigned addr, uint8 data) {
|
||||||
|
sa1.synchronize_cpu();
|
||||||
|
|
||||||
|
if(sa1.mmio.bbf == 0) {
|
||||||
|
//4bpp
|
||||||
|
unsigned shift = addr & 1;
|
||||||
|
addr = (addr >> 1) & (memory::cartram.size() - 1);
|
||||||
|
switch(shift) { default:
|
||||||
|
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
|
||||||
|
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//2bpp
|
||||||
|
unsigned shift = addr & 3;
|
||||||
|
addr = (addr >> 2) & (memory::cartram.size() - 1);
|
||||||
|
switch(shift) { default:
|
||||||
|
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
|
||||||
|
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
|
||||||
|
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;
|
||||||
|
case 3: data = (memory::cartram.read(addr) & 0x3f) | ((data & 3) << 6); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,55 @@
|
||||||
|
struct VBRBus : Bus {
|
||||||
|
void init();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SA1Bus : Bus {
|
||||||
|
void init();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSPROM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CPUIRAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SA1IRAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SA1BWRAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CC1BWRAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
bool dma;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitmapRAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
alwaysinline uint8 read(unsigned);
|
||||||
|
alwaysinline void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
extern StaticRAM iram;
|
||||||
|
|
||||||
|
extern VSPROM vsprom;
|
||||||
|
extern CPUIRAM cpuiram;
|
||||||
|
extern SA1IRAM sa1iram;
|
||||||
|
extern SA1BWRAM sa1bwram;
|
||||||
|
extern CC1BWRAM cc1bwram;
|
||||||
|
extern BitmapRAM bitmapram;
|
||||||
|
};
|
|
@ -0,0 +1,139 @@
|
||||||
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//direct data transfer
|
||||||
|
//====================
|
||||||
|
|
||||||
|
void SA1::dma_normal() {
|
||||||
|
while(mmio.dtc--) {
|
||||||
|
uint8 data = regs.mdr;
|
||||||
|
uint32 dsa = mmio.dsa++;
|
||||||
|
uint32 dda = mmio.dda++;
|
||||||
|
|
||||||
|
//source and destination cannot be the same
|
||||||
|
if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestBWRAM) continue;
|
||||||
|
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue;
|
||||||
|
|
||||||
|
switch(mmio.sd) {
|
||||||
|
case DMA::SourceROM: {
|
||||||
|
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
|
||||||
|
data = sa1bus.read(dsa);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DMA::SourceBWRAM: {
|
||||||
|
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
|
||||||
|
data = sa1bus.read(dsa);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DMA::SourceIRAM: {
|
||||||
|
data = memory::iram.read(dsa & 0x07ff);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(mmio.dd) {
|
||||||
|
case DMA::DestBWRAM: {
|
||||||
|
if((dda & 0x40e000) == 0x006000 || (dda & 0xf00000) == 0x400000) {
|
||||||
|
sa1bus.write(dda, data);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DMA::DestIRAM: {
|
||||||
|
memory::iram.write(dda & 0x07ff, data);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mmio.dma_irqfl = true;
|
||||||
|
if(mmio.dma_irqen) mmio.dma_irqcl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//((byte & 6) << 3) + (byte & 1) explanation:
|
||||||
|
//transforms a byte index (0-7) into a planar index:
|
||||||
|
//result[] = { 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||||
|
//works for 2bpp, 4bpp and 8bpp modes
|
||||||
|
|
||||||
|
//===========================
|
||||||
|
//type-1 character conversion
|
||||||
|
//===========================
|
||||||
|
|
||||||
|
void SA1::dma_cc1() {
|
||||||
|
memory::cc1bwram.dma = true;
|
||||||
|
mmio.chdma_irqfl = true;
|
||||||
|
if(mmio.chdma_irqen) {
|
||||||
|
mmio.chdma_irqcl = 0;
|
||||||
|
cpu.regs.irq = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SA1::dma_cc1_read(unsigned addr) {
|
||||||
|
//16 bytes/char (2bpp); 32 bytes/char (4bpp); 64 bytes/char (8bpp)
|
||||||
|
unsigned charmask = (1 << (6 - mmio.dmacb)) - 1;
|
||||||
|
|
||||||
|
if((addr & charmask) == 0) {
|
||||||
|
//buffer next character to I-RAM
|
||||||
|
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||||
|
unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb;
|
||||||
|
unsigned bwmask = memory::cartram.size() - 1;
|
||||||
|
unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
|
||||||
|
unsigned ty = (tile >> mmio.dmasize);
|
||||||
|
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
|
||||||
|
unsigned bwaddr = mmio.dsa + ty * 8 * bpl + tx * bpp;
|
||||||
|
|
||||||
|
for(unsigned y = 0; y < 8; y++) {
|
||||||
|
uint64 data = 0;
|
||||||
|
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||||
|
data |= (uint64)memory::cartram.read((bwaddr + byte) & bwmask) << (byte << 3);
|
||||||
|
}
|
||||||
|
bwaddr += bpl;
|
||||||
|
|
||||||
|
uint8 out[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
for(unsigned x = 0; x < 8; x++) {
|
||||||
|
out[0] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
out[1] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
if(mmio.dmacb == 2) continue;
|
||||||
|
out[2] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
out[3] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
if(mmio.dmacb == 1) continue;
|
||||||
|
out[4] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
out[5] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
out[6] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
out[7] |= (data & 1) << (7 - x); data >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||||
|
unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1);
|
||||||
|
memory::iram.write(p & 0x07ff, out[byte]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory::iram.read((mmio.dda + (addr & charmask)) & 0x07ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================
|
||||||
|
//type-2 character conversion
|
||||||
|
//===========================
|
||||||
|
|
||||||
|
void SA1::dma_cc2() {
|
||||||
|
//select register file index (0-7 or 8-15)
|
||||||
|
const uint8 *brf = &mmio.brf[(dma.line & 1) << 3];
|
||||||
|
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||||
|
unsigned addr = mmio.dda & 0x07ff;
|
||||||
|
addr &= ~((1 << (7 - mmio.dmacb)) - 1);
|
||||||
|
addr += (dma.line & 8) * bpp;
|
||||||
|
addr += (dma.line & 7) * 2;
|
||||||
|
|
||||||
|
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||||
|
uint8 output = 0;
|
||||||
|
for(unsigned bit = 0; bit < 8; bit++) {
|
||||||
|
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
|
||||||
|
}
|
||||||
|
memory::iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
|
||||||
|
}
|
||||||
|
|
||||||
|
dma.line = (dma.line + 1) & 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,11 @@
|
||||||
|
struct DMA {
|
||||||
|
enum CDEN { DmaNormal = 0, DmaCharConversion = 1 };
|
||||||
|
enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 };
|
||||||
|
enum DD { DestIRAM = 0, DestBWRAM = 1 };
|
||||||
|
unsigned line;
|
||||||
|
} dma;
|
||||||
|
|
||||||
|
void dma_normal();
|
||||||
|
void dma_cc1();
|
||||||
|
uint8 dma_cc1_read(unsigned addr);
|
||||||
|
void dma_cc2();
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
|
//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks)
|
||||||
|
//BW-RAM is accessed at ~5.37MHz (4 clock ticks)
|
||||||
|
//tick() == 2 clock ticks
|
||||||
|
//note: bus conflict delays are not emulated at this time
|
||||||
|
|
||||||
|
void SA1::op_io() {
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SA1::op_read(unsigned addr) {
|
||||||
|
tick();
|
||||||
|
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||||
|
return sa1bus.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::op_write(unsigned addr, uint8 data) {
|
||||||
|
tick();
|
||||||
|
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||||
|
sa1bus.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,5 @@
|
||||||
|
alwaysinline void op_io();
|
||||||
|
alwaysinline uint8 op_read(unsigned addr);
|
||||||
|
alwaysinline void op_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8_t vbr_read(unsigned addr);
|
|
@ -0,0 +1,631 @@
|
||||||
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
|
//BS-X flash carts, when present, are mapped to 0x400000+
|
||||||
|
Memory& SA1::mmio_access(unsigned &addr) {
|
||||||
|
if(!memory::bsxflash.data()) return memory::vsprom;
|
||||||
|
if(addr < 0x400000) return memory::vsprom;
|
||||||
|
addr &= 0x3fffff;
|
||||||
|
return bsxflash;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CCNT) SA-1 control
|
||||||
|
void SA1::mmio_w2200(uint8 data) {
|
||||||
|
if(mmio.sa1_resb && !(data & 0x80)) {
|
||||||
|
//reset SA-1 CPU
|
||||||
|
regs.pc.w = mmio.crv;
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
mmio.sa1_irq = (data & 0x80);
|
||||||
|
mmio.sa1_rdyb = (data & 0x40);
|
||||||
|
mmio.sa1_resb = (data & 0x20);
|
||||||
|
mmio.sa1_nmi = (data & 0x10);
|
||||||
|
mmio.smeg = (data & 0x0f);
|
||||||
|
|
||||||
|
if(mmio.sa1_irq) {
|
||||||
|
mmio.sa1_irqfl = true;
|
||||||
|
if(mmio.sa1_irqen) mmio.sa1_irqcl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mmio.sa1_nmi) {
|
||||||
|
mmio.sa1_nmifl = true;
|
||||||
|
if(mmio.sa1_nmien) mmio.sa1_nmicl = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SIE) S-CPU interrupt enable
|
||||||
|
void SA1::mmio_w2201(uint8 data) {
|
||||||
|
if(!mmio.cpu_irqen && (data & 0x80)) {
|
||||||
|
if(mmio.cpu_irqfl) {
|
||||||
|
mmio.cpu_irqcl = 0;
|
||||||
|
cpu.regs.irq = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mmio.chdma_irqen && (data & 0x20)) {
|
||||||
|
if(mmio.chdma_irqfl) {
|
||||||
|
mmio.chdma_irqcl = 0;
|
||||||
|
cpu.regs.irq = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mmio.cpu_irqen = (data & 0x80);
|
||||||
|
mmio.chdma_irqen = (data & 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SIC) S-CPU interrupt clear
|
||||||
|
void SA1::mmio_w2202(uint8 data) {
|
||||||
|
mmio.cpu_irqcl = (data & 0x80);
|
||||||
|
mmio.chdma_irqcl = (data & 0x20);
|
||||||
|
|
||||||
|
if(mmio.cpu_irqcl ) mmio.cpu_irqfl = false;
|
||||||
|
if(mmio.chdma_irqcl) mmio.chdma_irqfl = false;
|
||||||
|
|
||||||
|
if(!mmio.cpu_irqfl && !mmio.chdma_irqfl) cpu.regs.irq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CRV) SA-1 reset vector
|
||||||
|
void SA1::mmio_w2203(uint8 data) { mmio.crv = (mmio.crv & 0xff00) | data; }
|
||||||
|
void SA1::mmio_w2204(uint8 data) { mmio.crv = (data << 8) | (mmio.crv & 0xff); }
|
||||||
|
|
||||||
|
//(CNV) SA-1 NMI vector
|
||||||
|
void SA1::mmio_w2205(uint8 data) { mmio.cnv = (mmio.cnv & 0xff00) | data; }
|
||||||
|
void SA1::mmio_w2206(uint8 data) { mmio.cnv = (data << 8) | (mmio.cnv & 0xff); }
|
||||||
|
|
||||||
|
//(CIV) SA-1 IRQ vector
|
||||||
|
void SA1::mmio_w2207(uint8 data) { mmio.civ = (mmio.civ & 0xff00) | data; }
|
||||||
|
void SA1::mmio_w2208(uint8 data) { mmio.civ = (data << 8) | (mmio.civ & 0xff); }
|
||||||
|
|
||||||
|
//(SCNT) S-CPU control
|
||||||
|
void SA1::mmio_w2209(uint8 data) {
|
||||||
|
mmio.cpu_irq = (data & 0x80);
|
||||||
|
mmio.cpu_ivsw = (data & 0x40);
|
||||||
|
mmio.cpu_nvsw = (data & 0x10);
|
||||||
|
mmio.cmeg = (data & 0x0f);
|
||||||
|
|
||||||
|
if(mmio.cpu_irq) {
|
||||||
|
mmio.cpu_irqfl = true;
|
||||||
|
if(mmio.cpu_irqen) {
|
||||||
|
mmio.cpu_irqcl = 0;
|
||||||
|
cpu.regs.irq = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CIE) SA-1 interrupt enable
|
||||||
|
void SA1::mmio_w220a(uint8 data) {
|
||||||
|
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
|
||||||
|
if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0;
|
||||||
|
if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0;
|
||||||
|
if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0;
|
||||||
|
|
||||||
|
mmio.sa1_irqen = (data & 0x80);
|
||||||
|
mmio.timer_irqen = (data & 0x40);
|
||||||
|
mmio.dma_irqen = (data & 0x20);
|
||||||
|
mmio.sa1_nmien = (data & 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CIC) SA-1 interrupt clear
|
||||||
|
void SA1::mmio_w220b(uint8 data) {
|
||||||
|
mmio.sa1_irqcl = (data & 0x80);
|
||||||
|
mmio.timer_irqcl = (data & 0x40);
|
||||||
|
mmio.dma_irqcl = (data & 0x20);
|
||||||
|
mmio.sa1_nmicl = (data & 0x10);
|
||||||
|
|
||||||
|
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
|
||||||
|
if(mmio.timer_irqcl) mmio.timer_irqfl = false;
|
||||||
|
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
|
||||||
|
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SNV) S-CPU NMI vector
|
||||||
|
void SA1::mmio_w220c(uint8 data) { mmio.snv = (mmio.snv & 0xff00) | data; }
|
||||||
|
void SA1::mmio_w220d(uint8 data) { mmio.snv = (data << 8) | (mmio.snv & 0xff); }
|
||||||
|
|
||||||
|
//(SIV) S-CPU IRQ vector
|
||||||
|
void SA1::mmio_w220e(uint8 data) { mmio.siv = (mmio.siv & 0xff00) | data; }
|
||||||
|
void SA1::mmio_w220f(uint8 data) { mmio.siv = (data << 8) | (mmio.siv & 0xff); }
|
||||||
|
|
||||||
|
//(TMC) H/V timer control
|
||||||
|
void SA1::mmio_w2210(uint8 data) {
|
||||||
|
mmio.hvselb = (data & 0x80);
|
||||||
|
mmio.ven = (data & 0x02);
|
||||||
|
mmio.hen = (data & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CTR) SA-1 timer restart
|
||||||
|
void SA1::mmio_w2211(uint8 data) {
|
||||||
|
status.vcounter = 0;
|
||||||
|
status.hcounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(HCNT) H-count
|
||||||
|
void SA1::mmio_w2212(uint8 data) { mmio.hcnt = (mmio.hcnt & 0xff00) | (data << 0); }
|
||||||
|
void SA1::mmio_w2213(uint8 data) { mmio.hcnt = (mmio.hcnt & 0x00ff) | (data << 8); }
|
||||||
|
|
||||||
|
//(VCNT) V-count
|
||||||
|
void SA1::mmio_w2214(uint8 data) { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); }
|
||||||
|
void SA1::mmio_w2215(uint8 data) { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); }
|
||||||
|
|
||||||
|
//(CXB) Super MMC bank C
|
||||||
|
void SA1::mmio_w2220(uint8 data) {
|
||||||
|
mmio.cbmode = (data & 0x80);
|
||||||
|
mmio.cb = (data & 0x07);
|
||||||
|
|
||||||
|
unsigned addr = mmio.cb << 20;
|
||||||
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
|
if(mmio.cbmode == 0) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||||
|
} else {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(DXB) Super MMC bank D
|
||||||
|
void SA1::mmio_w2221(uint8 data) {
|
||||||
|
mmio.dbmode = (data & 0x80);
|
||||||
|
mmio.db = (data & 0x07);
|
||||||
|
|
||||||
|
unsigned addr = mmio.db << 20;
|
||||||
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
|
if(mmio.dbmode == 0) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||||
|
} else {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(EXB) Super MMC bank E
|
||||||
|
void SA1::mmio_w2222(uint8 data) {
|
||||||
|
mmio.ebmode = (data & 0x80);
|
||||||
|
mmio.eb = (data & 0x07);
|
||||||
|
|
||||||
|
unsigned addr = mmio.eb << 20;
|
||||||
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
|
if(mmio.ebmode == 0) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||||
|
} else {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(FXB) Super MMC bank F
|
||||||
|
void SA1::mmio_w2223(uint8 data) {
|
||||||
|
mmio.fbmode = (data & 0x80);
|
||||||
|
mmio.fb = (data & 0x07);
|
||||||
|
|
||||||
|
unsigned addr = mmio.fb << 20;
|
||||||
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
|
if(mmio.fbmode == 0) {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||||
|
} else {
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(BMAPS) S-CPU BW-RAM address mapping
|
||||||
|
void SA1::mmio_w2224(uint8 data) {
|
||||||
|
mmio.sbm = (data & 0x1f);
|
||||||
|
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||||
|
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(BMAP) SA-1 BW-RAM address mapping
|
||||||
|
void SA1::mmio_w2225(uint8 data) {
|
||||||
|
mmio.sw46 = (data & 0x80);
|
||||||
|
mmio.cbm = (data & 0x7f);
|
||||||
|
|
||||||
|
if(mmio.sw46 == 0) {
|
||||||
|
//$[40-43]:[0000-ffff] x 32 projection
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||||
|
} else {
|
||||||
|
//$[60-6f]:[0000-ffff] x 128 projection
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||||
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SWBE) S-CPU BW-RAM write enable
|
||||||
|
void SA1::mmio_w2226(uint8 data) {
|
||||||
|
mmio.swen = (data & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CWBE) SA-1 BW-RAM write enable
|
||||||
|
void SA1::mmio_w2227(uint8 data) {
|
||||||
|
mmio.cwen = (data & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(BWPA) BW-RAM write-protected area
|
||||||
|
void SA1::mmio_w2228(uint8 data) {
|
||||||
|
mmio.bwp = (data & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SIWP) S-CPU I-RAM write protection
|
||||||
|
void SA1::mmio_w2229(uint8 data) {
|
||||||
|
mmio.siwp = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CIWP) SA-1 I-RAM write protection
|
||||||
|
void SA1::mmio_w222a(uint8 data) {
|
||||||
|
mmio.ciwp = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(DCNT) DMA control
|
||||||
|
void SA1::mmio_w2230(uint8 data) {
|
||||||
|
mmio.dmaen = (data & 0x80);
|
||||||
|
mmio.dprio = (data & 0x40);
|
||||||
|
mmio.cden = (data & 0x20);
|
||||||
|
mmio.cdsel = (data & 0x10);
|
||||||
|
mmio.dd = (data & 0x04);
|
||||||
|
mmio.sd = (data & 0x03);
|
||||||
|
|
||||||
|
if(mmio.dmaen == 0) dma.line = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CDMA) character conversion DMA parameters
|
||||||
|
void SA1::mmio_w2231(uint8 data) {
|
||||||
|
mmio.chdend = (data & 0x80);
|
||||||
|
mmio.dmasize = (data >> 2) & 7;
|
||||||
|
mmio.dmacb = (data & 0x03);
|
||||||
|
|
||||||
|
if(mmio.chdend) memory::cc1bwram.dma = false;
|
||||||
|
if(mmio.dmasize > 5) mmio.dmasize = 5;
|
||||||
|
if(mmio.dmacb > 2) mmio.dmacb = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(SDA) DMA source device start address
|
||||||
|
void SA1::mmio_w2232(uint8 data) { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); }
|
||||||
|
void SA1::mmio_w2233(uint8 data) { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); }
|
||||||
|
void SA1::mmio_w2234(uint8 data) { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); }
|
||||||
|
|
||||||
|
//(DDA) DMA destination start address
|
||||||
|
void SA1::mmio_w2235(uint8 data) {
|
||||||
|
mmio.dda = (mmio.dda & 0xffff00) | (data << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::mmio_w2236(uint8 data) {
|
||||||
|
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
|
||||||
|
|
||||||
|
if(mmio.dmaen == true) {
|
||||||
|
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
|
||||||
|
dma_normal();
|
||||||
|
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
|
||||||
|
dma_cc1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::mmio_w2237(uint8 data) {
|
||||||
|
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
|
||||||
|
|
||||||
|
if(mmio.dmaen == true) {
|
||||||
|
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
|
||||||
|
dma_normal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(DTC) DMA terminal counter
|
||||||
|
void SA1::mmio_w2238(uint8 data) { mmio.dtc = (mmio.dtc & 0xff00) | (data << 0); }
|
||||||
|
void SA1::mmio_w2239(uint8 data) { mmio.dtc = (mmio.dtc & 0x00ff) | (data << 8); }
|
||||||
|
|
||||||
|
//(BBF) BW-RAM bitmap format
|
||||||
|
void SA1::mmio_w223f(uint8 data) {
|
||||||
|
mmio.bbf = (data & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(BRF) bitmap register files
|
||||||
|
void SA1::mmio_w2240(uint8 data) { mmio.brf[ 0] = data; }
|
||||||
|
void SA1::mmio_w2241(uint8 data) { mmio.brf[ 1] = data; }
|
||||||
|
void SA1::mmio_w2242(uint8 data) { mmio.brf[ 2] = data; }
|
||||||
|
void SA1::mmio_w2243(uint8 data) { mmio.brf[ 3] = data; }
|
||||||
|
void SA1::mmio_w2244(uint8 data) { mmio.brf[ 4] = data; }
|
||||||
|
void SA1::mmio_w2245(uint8 data) { mmio.brf[ 5] = data; }
|
||||||
|
void SA1::mmio_w2246(uint8 data) { mmio.brf[ 6] = data; }
|
||||||
|
void SA1::mmio_w2247(uint8 data) { mmio.brf[ 7] = data;
|
||||||
|
if(mmio.dmaen == true) {
|
||||||
|
if(mmio.cden == 1 && mmio.cdsel == 0) {
|
||||||
|
dma_cc2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::mmio_w2248(uint8 data) { mmio.brf[ 8] = data; }
|
||||||
|
void SA1::mmio_w2249(uint8 data) { mmio.brf[ 9] = data; }
|
||||||
|
void SA1::mmio_w224a(uint8 data) { mmio.brf[10] = data; }
|
||||||
|
void SA1::mmio_w224b(uint8 data) { mmio.brf[11] = data; }
|
||||||
|
void SA1::mmio_w224c(uint8 data) { mmio.brf[12] = data; }
|
||||||
|
void SA1::mmio_w224d(uint8 data) { mmio.brf[13] = data; }
|
||||||
|
void SA1::mmio_w224e(uint8 data) { mmio.brf[14] = data; }
|
||||||
|
void SA1::mmio_w224f(uint8 data) { mmio.brf[15] = data;
|
||||||
|
if(mmio.dmaen == true) {
|
||||||
|
if(mmio.cden == 1 && mmio.cdsel == 0) {
|
||||||
|
dma_cc2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(MCNT) arithmetic control
|
||||||
|
void SA1::mmio_w2250(uint8 data) {
|
||||||
|
mmio.acm = (data & 0x02);
|
||||||
|
mmio.md = (data & 0x01);
|
||||||
|
|
||||||
|
if(mmio.acm) mmio.mr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(MAL) multiplicand / dividend low
|
||||||
|
void SA1::mmio_w2251(uint8 data) {
|
||||||
|
mmio.ma = (mmio.ma & 0xff00) | data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(MAH) multiplicand / dividend high
|
||||||
|
void SA1::mmio_w2252(uint8 data) {
|
||||||
|
mmio.ma = (data << 8) | (mmio.ma & 0x00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
//(MBL) multiplier / divisor low
|
||||||
|
void SA1::mmio_w2253(uint8 data) {
|
||||||
|
mmio.mb = (mmio.mb & 0xff00) | data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(MBH) multiplier / divisor high
|
||||||
|
//multiplication / cumulative sum only resets MB
|
||||||
|
//division resets both MA and MB
|
||||||
|
void SA1::mmio_w2254(uint8 data) {
|
||||||
|
mmio.mb = (data << 8) | (mmio.mb & 0x00ff);
|
||||||
|
|
||||||
|
if(mmio.acm == 0) {
|
||||||
|
if(mmio.md == 0) {
|
||||||
|
//signed multiplication
|
||||||
|
mmio.mr = (int16)mmio.ma * (int16)mmio.mb;
|
||||||
|
mmio.mb = 0;
|
||||||
|
} else {
|
||||||
|
//unsigned division
|
||||||
|
if(mmio.mb == 0) {
|
||||||
|
mmio.mr = 0;
|
||||||
|
} else {
|
||||||
|
int16 quotient = (int16)mmio.ma / (uint16)mmio.mb;
|
||||||
|
uint16 remainder = (int16)mmio.ma % (uint16)mmio.mb;
|
||||||
|
mmio.mr = (remainder << 16) | quotient;
|
||||||
|
}
|
||||||
|
mmio.ma = 0;
|
||||||
|
mmio.mb = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//sigma (accumulative multiplication)
|
||||||
|
mmio.mr += (int16)mmio.ma * (int16)mmio.mb;
|
||||||
|
mmio.overflow = (mmio.mr >= (1ULL << 40));
|
||||||
|
mmio.mr &= (1ULL << 40) - 1;
|
||||||
|
mmio.mb = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(VBD) variable-length bit processing
|
||||||
|
void SA1::mmio_w2258(uint8 data) {
|
||||||
|
mmio.hl = (data & 0x80);
|
||||||
|
mmio.vb = (data & 0x0f);
|
||||||
|
if(mmio.vb == 0) mmio.vb = 16;
|
||||||
|
|
||||||
|
if(mmio.hl == 0) {
|
||||||
|
//fixed mode
|
||||||
|
mmio.vbit += mmio.vb;
|
||||||
|
mmio.va += (mmio.vbit >> 3);
|
||||||
|
mmio.vbit &= 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//(VDA) variable-length bit game pak ROM start address
|
||||||
|
void SA1::mmio_w2259(uint8 data) { mmio.va = (mmio.va & 0xffff00) | (data << 0); }
|
||||||
|
void SA1::mmio_w225a(uint8 data) { mmio.va = (mmio.va & 0xff00ff) | (data << 8); }
|
||||||
|
void SA1::mmio_w225b(uint8 data) { mmio.va = (mmio.va & 0x00ffff) | (data << 16); mmio.vbit = 0; }
|
||||||
|
|
||||||
|
//(SFR) S-CPU flag read
|
||||||
|
uint8 SA1::mmio_r2300() {
|
||||||
|
uint8 data;
|
||||||
|
data = mmio.cpu_irqfl << 7;
|
||||||
|
data |= mmio.cpu_ivsw << 6;
|
||||||
|
data |= mmio.chdma_irqfl << 5;
|
||||||
|
data |= mmio.cpu_nvsw << 4;
|
||||||
|
data |= mmio.cmeg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(CFR) SA-1 flag read
|
||||||
|
uint8 SA1::mmio_r2301() {
|
||||||
|
uint8 data;
|
||||||
|
data = mmio.sa1_irqfl << 7;
|
||||||
|
data |= mmio.timer_irqfl << 6;
|
||||||
|
data |= mmio.dma_irqfl << 5;
|
||||||
|
data |= mmio.sa1_nmifl << 4;
|
||||||
|
data |= mmio.smeg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(HCR) hcounter read
|
||||||
|
uint8 SA1::mmio_r2302() {
|
||||||
|
//latch counters
|
||||||
|
mmio.hcr = status.hcounter >> 2;
|
||||||
|
mmio.vcr = status.vcounter;
|
||||||
|
return mmio.hcr >> 0; }
|
||||||
|
uint8 SA1::mmio_r2303() { return mmio.hcr >> 8; }
|
||||||
|
|
||||||
|
//(VCR) vcounter read
|
||||||
|
uint8 SA1::mmio_r2304() { return mmio.vcr >> 0; }
|
||||||
|
uint8 SA1::mmio_r2305() { return mmio.vcr >> 8; }
|
||||||
|
|
||||||
|
//(MR) arithmetic result
|
||||||
|
uint8 SA1::mmio_r2306() { return mmio.mr >> 0; }
|
||||||
|
uint8 SA1::mmio_r2307() { return mmio.mr >> 8; }
|
||||||
|
uint8 SA1::mmio_r2308() { return mmio.mr >> 16; }
|
||||||
|
uint8 SA1::mmio_r2309() { return mmio.mr >> 24; }
|
||||||
|
uint8 SA1::mmio_r230a() { return mmio.mr >> 32; }
|
||||||
|
|
||||||
|
//(OF) arithmetic overflow flag
|
||||||
|
uint8 SA1::mmio_r230b() { return mmio.overflow << 7; }
|
||||||
|
|
||||||
|
//(VDPL) variable-length data read port low
|
||||||
|
uint8 SA1::mmio_r230c() {
|
||||||
|
uint32 data = (vbrbus.read(mmio.va + 0) << 0)
|
||||||
|
| (vbrbus.read(mmio.va + 1) << 8)
|
||||||
|
| (vbrbus.read(mmio.va + 2) << 16);
|
||||||
|
data >>= mmio.vbit;
|
||||||
|
return data >> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(VDPH) variable-length data read port high
|
||||||
|
uint8 SA1::mmio_r230d() {
|
||||||
|
uint32 data = (vbrbus.read(mmio.va + 0) << 0)
|
||||||
|
| (vbrbus.read(mmio.va + 1) << 8)
|
||||||
|
| (vbrbus.read(mmio.va + 2) << 16);
|
||||||
|
data >>= mmio.vbit;
|
||||||
|
|
||||||
|
if(mmio.hl == 1) {
|
||||||
|
//auto-increment mode
|
||||||
|
mmio.vbit += mmio.vb;
|
||||||
|
mmio.va += (mmio.vbit >> 3);
|
||||||
|
mmio.vbit &= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(VC) version code register
|
||||||
|
uint8 SA1::mmio_r230e() {
|
||||||
|
return 0x01; //true value unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SA1::mmio_read(unsigned addr) {
|
||||||
|
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2300: return mmio_r2300();
|
||||||
|
case 0x2301: return mmio_r2301();
|
||||||
|
case 0x2302: return mmio_r2302();
|
||||||
|
case 0x2303: return mmio_r2303();
|
||||||
|
case 0x2304: return mmio_r2304();
|
||||||
|
case 0x2305: return mmio_r2305();
|
||||||
|
case 0x2306: return mmio_r2306();
|
||||||
|
case 0x2307: return mmio_r2307();
|
||||||
|
case 0x2308: return mmio_r2308();
|
||||||
|
case 0x2309: return mmio_r2309();
|
||||||
|
case 0x230a: return mmio_r230a();
|
||||||
|
case 0x230b: return mmio_r230b();
|
||||||
|
case 0x230c: return mmio_r230c();
|
||||||
|
case 0x230d: return mmio_r230d();
|
||||||
|
case 0x230e: return mmio_r230e();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
case 0x2200: return mmio_w2200(data);
|
||||||
|
case 0x2201: return mmio_w2201(data);
|
||||||
|
case 0x2202: return mmio_w2202(data);
|
||||||
|
case 0x2203: return mmio_w2203(data);
|
||||||
|
case 0x2204: return mmio_w2204(data);
|
||||||
|
case 0x2205: return mmio_w2205(data);
|
||||||
|
case 0x2206: return mmio_w2206(data);
|
||||||
|
case 0x2207: return mmio_w2207(data);
|
||||||
|
case 0x2208: return mmio_w2208(data);
|
||||||
|
case 0x2209: return mmio_w2209(data);
|
||||||
|
case 0x220a: return mmio_w220a(data);
|
||||||
|
case 0x220b: return mmio_w220b(data);
|
||||||
|
case 0x220c: return mmio_w220c(data);
|
||||||
|
case 0x220d: return mmio_w220d(data);
|
||||||
|
case 0x220e: return mmio_w220e(data);
|
||||||
|
case 0x220f: return mmio_w220f(data);
|
||||||
|
|
||||||
|
case 0x2210: return mmio_w2210(data);
|
||||||
|
case 0x2211: return mmio_w2211(data);
|
||||||
|
case 0x2212: return mmio_w2212(data);
|
||||||
|
case 0x2213: return mmio_w2213(data);
|
||||||
|
case 0x2214: return mmio_w2214(data);
|
||||||
|
case 0x2215: return mmio_w2215(data);
|
||||||
|
|
||||||
|
case 0x2220: return mmio_w2220(data);
|
||||||
|
case 0x2221: return mmio_w2221(data);
|
||||||
|
case 0x2222: return mmio_w2222(data);
|
||||||
|
case 0x2223: return mmio_w2223(data);
|
||||||
|
case 0x2224: return mmio_w2224(data);
|
||||||
|
case 0x2225: return mmio_w2225(data);
|
||||||
|
case 0x2226: return mmio_w2226(data);
|
||||||
|
case 0x2227: return mmio_w2227(data);
|
||||||
|
case 0x2228: return mmio_w2228(data);
|
||||||
|
case 0x2229: return mmio_w2229(data);
|
||||||
|
case 0x222a: return mmio_w222a(data);
|
||||||
|
|
||||||
|
case 0x2230: return mmio_w2230(data);
|
||||||
|
case 0x2231: return mmio_w2231(data);
|
||||||
|
case 0x2232: return mmio_w2232(data);
|
||||||
|
case 0x2233: return mmio_w2233(data);
|
||||||
|
case 0x2234: return mmio_w2234(data);
|
||||||
|
case 0x2235: return mmio_w2235(data);
|
||||||
|
case 0x2236: return mmio_w2236(data);
|
||||||
|
case 0x2237: return mmio_w2237(data);
|
||||||
|
case 0x2238: return mmio_w2238(data);
|
||||||
|
case 0x2239: return mmio_w2239(data);
|
||||||
|
|
||||||
|
case 0x223f: return mmio_w223f(data);
|
||||||
|
case 0x2240: return mmio_w2240(data);
|
||||||
|
case 0x2241: return mmio_w2241(data);
|
||||||
|
case 0x2242: return mmio_w2242(data);
|
||||||
|
case 0x2243: return mmio_w2243(data);
|
||||||
|
case 0x2244: return mmio_w2244(data);
|
||||||
|
case 0x2245: return mmio_w2245(data);
|
||||||
|
case 0x2246: return mmio_w2246(data);
|
||||||
|
case 0x2247: return mmio_w2247(data);
|
||||||
|
case 0x2248: return mmio_w2248(data);
|
||||||
|
case 0x2249: return mmio_w2249(data);
|
||||||
|
case 0x224a: return mmio_w224a(data);
|
||||||
|
case 0x224b: return mmio_w224b(data);
|
||||||
|
case 0x224c: return mmio_w224c(data);
|
||||||
|
case 0x224d: return mmio_w224d(data);
|
||||||
|
case 0x224e: return mmio_w224e(data);
|
||||||
|
case 0x224f: return mmio_w224f(data);
|
||||||
|
|
||||||
|
case 0x2250: return mmio_w2250(data);
|
||||||
|
case 0x2251: return mmio_w2251(data);
|
||||||
|
case 0x2252: return mmio_w2252(data);
|
||||||
|
case 0x2253: return mmio_w2253(data);
|
||||||
|
case 0x2254: return mmio_w2254(data);
|
||||||
|
|
||||||
|
case 0x2258: return mmio_w2258(data);
|
||||||
|
case 0x2259: return mmio_w2259(data);
|
||||||
|
case 0x225a: return mmio_w225a(data);
|
||||||
|
case 0x225b: return mmio_w225b(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,256 @@
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
Memory& mmio_access(unsigned &addr);
|
||||||
|
|
||||||
|
struct MMIO {
|
||||||
|
//$2200 CCNT
|
||||||
|
bool sa1_irq;
|
||||||
|
bool sa1_rdyb;
|
||||||
|
bool sa1_resb;
|
||||||
|
bool sa1_nmi;
|
||||||
|
uint8 smeg;
|
||||||
|
|
||||||
|
//$2201 SIE
|
||||||
|
bool cpu_irqen;
|
||||||
|
bool chdma_irqen;
|
||||||
|
|
||||||
|
//$2202 SIC
|
||||||
|
bool cpu_irqcl;
|
||||||
|
bool chdma_irqcl;
|
||||||
|
|
||||||
|
//$2203,$2204 CRV
|
||||||
|
uint16 crv;
|
||||||
|
|
||||||
|
//$2205,$2206 CNV
|
||||||
|
uint16 cnv;
|
||||||
|
|
||||||
|
//$2207,$2208 CIV
|
||||||
|
uint16 civ;
|
||||||
|
|
||||||
|
//$2209 SCNT
|
||||||
|
bool cpu_irq;
|
||||||
|
bool cpu_ivsw;
|
||||||
|
bool cpu_nvsw;
|
||||||
|
uint8 cmeg;
|
||||||
|
|
||||||
|
//$220a CIE
|
||||||
|
bool sa1_irqen;
|
||||||
|
bool timer_irqen;
|
||||||
|
bool dma_irqen;
|
||||||
|
bool sa1_nmien;
|
||||||
|
|
||||||
|
//$220b CIC
|
||||||
|
bool sa1_irqcl;
|
||||||
|
bool timer_irqcl;
|
||||||
|
bool dma_irqcl;
|
||||||
|
bool sa1_nmicl;
|
||||||
|
|
||||||
|
//$220c,$220d SNV
|
||||||
|
uint16 snv;
|
||||||
|
|
||||||
|
//$220e,$220f SIV
|
||||||
|
uint16 siv;
|
||||||
|
|
||||||
|
//$2210 TMC
|
||||||
|
bool hvselb;
|
||||||
|
bool ven;
|
||||||
|
bool hen;
|
||||||
|
|
||||||
|
//$2212,$2213
|
||||||
|
uint16 hcnt;
|
||||||
|
|
||||||
|
//$2214,$2215
|
||||||
|
uint16 vcnt;
|
||||||
|
|
||||||
|
//$2220 CXB
|
||||||
|
bool cbmode;
|
||||||
|
uint8 cb;
|
||||||
|
|
||||||
|
//$2221 DXB
|
||||||
|
bool dbmode;
|
||||||
|
uint8 db;
|
||||||
|
|
||||||
|
//$2222 EXB
|
||||||
|
bool ebmode;
|
||||||
|
uint8 eb;
|
||||||
|
|
||||||
|
//$2223 FXB
|
||||||
|
bool fbmode;
|
||||||
|
uint8 fb;
|
||||||
|
|
||||||
|
//$2224 BMAPS
|
||||||
|
uint8 sbm;
|
||||||
|
|
||||||
|
//$2225 BMAP
|
||||||
|
bool sw46;
|
||||||
|
uint8 cbm;
|
||||||
|
|
||||||
|
//$2226 SBWE
|
||||||
|
bool swen;
|
||||||
|
|
||||||
|
//$2227 CBWE
|
||||||
|
bool cwen;
|
||||||
|
|
||||||
|
//$2228 BWPA
|
||||||
|
uint8 bwp;
|
||||||
|
|
||||||
|
//$2229 SIWP
|
||||||
|
uint8 siwp;
|
||||||
|
|
||||||
|
//$222a CIWP
|
||||||
|
uint8 ciwp;
|
||||||
|
|
||||||
|
//$2230 DCNT
|
||||||
|
bool dmaen;
|
||||||
|
bool dprio;
|
||||||
|
bool cden;
|
||||||
|
bool cdsel;
|
||||||
|
bool dd;
|
||||||
|
uint8 sd;
|
||||||
|
|
||||||
|
//$2231 CDMA
|
||||||
|
bool chdend;
|
||||||
|
uint8 dmasize;
|
||||||
|
uint8 dmacb;
|
||||||
|
|
||||||
|
//$2232-$2234 SDA
|
||||||
|
uint32 dsa;
|
||||||
|
|
||||||
|
//$2235-$2237 DDA
|
||||||
|
uint32 dda;
|
||||||
|
|
||||||
|
//$2238,$2239 DTC
|
||||||
|
uint16 dtc;
|
||||||
|
|
||||||
|
//$223f BBF
|
||||||
|
bool bbf;
|
||||||
|
|
||||||
|
//$2240-224f BRF
|
||||||
|
uint8 brf[16];
|
||||||
|
|
||||||
|
//$2250 MCNT
|
||||||
|
bool acm;
|
||||||
|
bool md;
|
||||||
|
|
||||||
|
//$2251,$2252 MA
|
||||||
|
uint16 ma;
|
||||||
|
|
||||||
|
//$2253,$2254 MB
|
||||||
|
uint16 mb;
|
||||||
|
|
||||||
|
//$2258 VBD
|
||||||
|
bool hl;
|
||||||
|
uint8 vb;
|
||||||
|
|
||||||
|
//$2259-$225b VDA
|
||||||
|
uint32 va;
|
||||||
|
uint8 vbit;
|
||||||
|
|
||||||
|
//$2300 SFR
|
||||||
|
bool cpu_irqfl;
|
||||||
|
bool chdma_irqfl;
|
||||||
|
|
||||||
|
//$2301 CFR
|
||||||
|
bool sa1_irqfl;
|
||||||
|
bool timer_irqfl;
|
||||||
|
bool dma_irqfl;
|
||||||
|
bool sa1_nmifl;
|
||||||
|
|
||||||
|
//$2302,$2303 HCR
|
||||||
|
uint16 hcr;
|
||||||
|
|
||||||
|
//$2304,$2305 VCR
|
||||||
|
uint16 vcr;
|
||||||
|
|
||||||
|
//$2306-230a MR
|
||||||
|
uint64 mr;
|
||||||
|
|
||||||
|
//$230b OF
|
||||||
|
bool overflow;
|
||||||
|
} mmio;
|
||||||
|
|
||||||
|
void mmio_w2200(uint8); //CCNT
|
||||||
|
void mmio_w2201(uint8); //SIE
|
||||||
|
void mmio_w2202(uint8); //SIC
|
||||||
|
void mmio_w2203(uint8); //CRVL
|
||||||
|
void mmio_w2204(uint8); //CRVH
|
||||||
|
void mmio_w2205(uint8); //CNVL
|
||||||
|
void mmio_w2206(uint8); //CNVH
|
||||||
|
void mmio_w2207(uint8); //CIVL
|
||||||
|
void mmio_w2208(uint8); //CIVH
|
||||||
|
void mmio_w2209(uint8); //SCNT
|
||||||
|
void mmio_w220a(uint8); //CIE
|
||||||
|
void mmio_w220b(uint8); //CIC
|
||||||
|
void mmio_w220c(uint8); //SNVL
|
||||||
|
void mmio_w220d(uint8); //SNVH
|
||||||
|
void mmio_w220e(uint8); //SIVL
|
||||||
|
void mmio_w220f(uint8); //SIVH
|
||||||
|
void mmio_w2210(uint8); //TMC
|
||||||
|
void mmio_w2211(uint8); //CTR
|
||||||
|
void mmio_w2212(uint8); //HCNTL
|
||||||
|
void mmio_w2213(uint8); //HCNTH
|
||||||
|
void mmio_w2214(uint8); //VCNTL
|
||||||
|
void mmio_w2215(uint8); //VCNTH
|
||||||
|
void mmio_w2220(uint8); //CXB
|
||||||
|
void mmio_w2221(uint8); //DXB
|
||||||
|
void mmio_w2222(uint8); //EXB
|
||||||
|
void mmio_w2223(uint8); //FXB
|
||||||
|
void mmio_w2224(uint8); //BMAPS
|
||||||
|
void mmio_w2225(uint8); //BMAP
|
||||||
|
void mmio_w2226(uint8); //SBWE
|
||||||
|
void mmio_w2227(uint8); //CBWE
|
||||||
|
void mmio_w2228(uint8); //BWPA
|
||||||
|
void mmio_w2229(uint8); //SIWP
|
||||||
|
void mmio_w222a(uint8); //CIWP
|
||||||
|
void mmio_w2230(uint8); //DCNT
|
||||||
|
void mmio_w2231(uint8); //CDMA
|
||||||
|
void mmio_w2232(uint8); //SDAL
|
||||||
|
void mmio_w2233(uint8); //SDAH
|
||||||
|
void mmio_w2234(uint8); //SDAB
|
||||||
|
void mmio_w2235(uint8); //DDAL
|
||||||
|
void mmio_w2236(uint8); //DDAH
|
||||||
|
void mmio_w2237(uint8); //DDAB
|
||||||
|
void mmio_w2238(uint8); //DTCL
|
||||||
|
void mmio_w2239(uint8); //DTCH
|
||||||
|
void mmio_w223f(uint8); //BBF
|
||||||
|
void mmio_w2240(uint8); //BRF0
|
||||||
|
void mmio_w2241(uint8); //BRF1
|
||||||
|
void mmio_w2242(uint8); //BRF2
|
||||||
|
void mmio_w2243(uint8); //BRF3
|
||||||
|
void mmio_w2244(uint8); //BRF4
|
||||||
|
void mmio_w2245(uint8); //BRF5
|
||||||
|
void mmio_w2246(uint8); //BRF6
|
||||||
|
void mmio_w2247(uint8); //BRF7
|
||||||
|
void mmio_w2248(uint8); //BRF8
|
||||||
|
void mmio_w2249(uint8); //BRF9
|
||||||
|
void mmio_w224a(uint8); //BRFA
|
||||||
|
void mmio_w224b(uint8); //BRFB
|
||||||
|
void mmio_w224c(uint8); //BRFC
|
||||||
|
void mmio_w224d(uint8); //BRFD
|
||||||
|
void mmio_w224e(uint8); //BRFE
|
||||||
|
void mmio_w224f(uint8); //BRFF
|
||||||
|
void mmio_w2250(uint8); //MCNT
|
||||||
|
void mmio_w2251(uint8); //MAL
|
||||||
|
void mmio_w2252(uint8); //MAH
|
||||||
|
void mmio_w2253(uint8); //MBL
|
||||||
|
void mmio_w2254(uint8); //MBH
|
||||||
|
void mmio_w2258(uint8); //VBD
|
||||||
|
void mmio_w2259(uint8); //VDAL
|
||||||
|
void mmio_w225a(uint8); //VDAH
|
||||||
|
void mmio_w225b(uint8); //VDAB
|
||||||
|
|
||||||
|
uint8 mmio_r2300(); //SFR
|
||||||
|
uint8 mmio_r2301(); //CFR
|
||||||
|
uint8 mmio_r2302(); //HCRL
|
||||||
|
uint8 mmio_r2303(); //HCRH
|
||||||
|
uint8 mmio_r2304(); //VCRL
|
||||||
|
uint8 mmio_r2305(); //VCRH
|
||||||
|
uint8 mmio_r2306(); //MR [00-07]
|
||||||
|
uint8 mmio_r2307(); //MR [08-15]
|
||||||
|
uint8 mmio_r2308(); //MR [16-23]
|
||||||
|
uint8 mmio_r2309(); //MR [24-31]
|
||||||
|
uint8 mmio_r230a(); //MR [32-40]
|
||||||
|
uint8 mmio_r230b(); //OF
|
||||||
|
uint8 mmio_r230c(); //VDPL
|
||||||
|
uint8 mmio_r230d(); //VDPH
|
||||||
|
uint8 mmio_r230e(); //VC
|
|
@ -0,0 +1,329 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SA1_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
SA1 sa1;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#include "bus/bus.cpp"
|
||||||
|
#include "dma/dma.cpp"
|
||||||
|
#include "memory/memory.cpp"
|
||||||
|
#include "mmio/mmio.cpp"
|
||||||
|
|
||||||
|
void SA1::Enter() { sa1.enter(); }
|
||||||
|
|
||||||
|
void SA1::enter() {
|
||||||
|
while(true) {
|
||||||
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||||
|
//SA-1 co-processor is asleep
|
||||||
|
tick();
|
||||||
|
synchronize_cpu();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.interrupt_pending) {
|
||||||
|
status.interrupt_pending = false;
|
||||||
|
interrupt(status.interrupt_vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
(this->*opcode_table[op_readpc()])();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::last_cycle() {
|
||||||
|
if(mmio.sa1_nmi && !mmio.sa1_nmicl) {
|
||||||
|
status.interrupt_pending = true;
|
||||||
|
status.interrupt_vector = mmio.cnv;
|
||||||
|
mmio.sa1_nmifl = true;
|
||||||
|
mmio.sa1_nmicl = 1;
|
||||||
|
regs.wai = false;
|
||||||
|
} else if(!regs.p.i) {
|
||||||
|
if(mmio.timer_irqen && !mmio.timer_irqcl) {
|
||||||
|
status.interrupt_pending = true;
|
||||||
|
status.interrupt_vector = mmio.civ;
|
||||||
|
mmio.timer_irqfl = true;
|
||||||
|
regs.wai = false;
|
||||||
|
} else if(mmio.dma_irqen && !mmio.dma_irqcl) {
|
||||||
|
status.interrupt_pending = true;
|
||||||
|
status.interrupt_vector = mmio.civ;
|
||||||
|
mmio.dma_irqfl = true;
|
||||||
|
regs.wai = false;
|
||||||
|
} else if(mmio.sa1_irq && !mmio.sa1_irqcl) {
|
||||||
|
status.interrupt_pending = true;
|
||||||
|
status.interrupt_vector = mmio.civ;
|
||||||
|
mmio.sa1_irqfl = true;
|
||||||
|
regs.wai = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::interrupt(uint16 vector) {
|
||||||
|
SA1::op_read(regs.pc.d);
|
||||||
|
SA1::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);
|
||||||
|
regs.pc.w = vector;
|
||||||
|
regs.pc.b = 0x00;
|
||||||
|
regs.p.i = 1;
|
||||||
|
regs.p.d = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SA1::interrupt_pending() {
|
||||||
|
return status.interrupt_pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::tick() {
|
||||||
|
step(2);
|
||||||
|
if(++status.tick_counter == 0) synchronize_cpu();
|
||||||
|
|
||||||
|
//adjust counters:
|
||||||
|
//note that internally, status counters are in clocks;
|
||||||
|
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
||||||
|
if(mmio.hvselb == 0) {
|
||||||
|
//HV timer
|
||||||
|
status.hcounter += 2;
|
||||||
|
if(status.hcounter >= 1364) {
|
||||||
|
status.hcounter = 0;
|
||||||
|
if(++status.vcounter >= status.scanlines) status.vcounter = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//linear timer
|
||||||
|
status.hcounter += 2;
|
||||||
|
status.vcounter += (status.hcounter >> 11);
|
||||||
|
status.hcounter &= 0x07ff;
|
||||||
|
status.vcounter &= 0x01ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//test counters for timer IRQ
|
||||||
|
switch((mmio.ven << 1) + (mmio.hen << 0)) {
|
||||||
|
case 0: break;
|
||||||
|
case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
|
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break;
|
||||||
|
case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::trigger_irq() {
|
||||||
|
mmio.timer_irqfl = true;
|
||||||
|
if(mmio.timer_irqen) mmio.timer_irqcl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::power() {
|
||||||
|
regs.a = regs.x = regs.y = 0x0000;
|
||||||
|
regs.s = 0x01ff;
|
||||||
|
vbrbus.init();
|
||||||
|
sa1bus.init();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SA1::reset() {
|
||||||
|
create(SA1::Enter, system.cpu_frequency());
|
||||||
|
|
||||||
|
memory::cc1bwram.dma = false;
|
||||||
|
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
|
||||||
|
memory::iram.write(addr, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.pc.d = 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;
|
||||||
|
CPUcore::update_table();
|
||||||
|
|
||||||
|
status.tick_counter = 0;
|
||||||
|
|
||||||
|
status.interrupt_pending = false;
|
||||||
|
status.interrupt_vector = 0x0000;
|
||||||
|
|
||||||
|
status.scanlines = (system.region() == System::Region::NTSC ? 262 : 312);
|
||||||
|
status.vcounter = 0;
|
||||||
|
status.hcounter = 0;
|
||||||
|
|
||||||
|
dma.line = 0;
|
||||||
|
|
||||||
|
//$2200 CCNT
|
||||||
|
mmio.sa1_irq = false;
|
||||||
|
mmio.sa1_rdyb = false;
|
||||||
|
mmio.sa1_resb = true;
|
||||||
|
mmio.sa1_nmi = false;
|
||||||
|
mmio.smeg = 0;
|
||||||
|
|
||||||
|
//$2201 SIE
|
||||||
|
mmio.cpu_irqen = false;
|
||||||
|
mmio.chdma_irqen = false;
|
||||||
|
|
||||||
|
//$2202 SIC
|
||||||
|
mmio.cpu_irqcl = false;
|
||||||
|
mmio.chdma_irqcl = false;
|
||||||
|
|
||||||
|
//$2203,$2204 CRV
|
||||||
|
mmio.crv = 0x0000;
|
||||||
|
|
||||||
|
//$2205,$2206 CNV
|
||||||
|
mmio.cnv = 0x0000;
|
||||||
|
|
||||||
|
//$2207,$2208 CIV
|
||||||
|
mmio.civ = 0x0000;
|
||||||
|
|
||||||
|
//$2209 SCNT
|
||||||
|
mmio.cpu_irq = false;
|
||||||
|
mmio.cpu_ivsw = false;
|
||||||
|
mmio.cpu_nvsw = false;
|
||||||
|
mmio.cmeg = 0;
|
||||||
|
|
||||||
|
//$220a CIE
|
||||||
|
mmio.sa1_irqen = false;
|
||||||
|
mmio.timer_irqen = false;
|
||||||
|
mmio.dma_irqen = false;
|
||||||
|
mmio.sa1_nmien = false;
|
||||||
|
|
||||||
|
//$220b CIC
|
||||||
|
mmio.sa1_irqcl = false;
|
||||||
|
mmio.timer_irqcl = false;
|
||||||
|
mmio.dma_irqcl = false;
|
||||||
|
mmio.sa1_nmicl = false;
|
||||||
|
|
||||||
|
//$220c,$220d SNV
|
||||||
|
mmio.snv = 0x0000;
|
||||||
|
|
||||||
|
//$220e,$220f SIV
|
||||||
|
mmio.siv = 0x0000;
|
||||||
|
|
||||||
|
//$2210
|
||||||
|
mmio.hvselb = false;
|
||||||
|
mmio.ven = false;
|
||||||
|
mmio.hen = false;
|
||||||
|
|
||||||
|
//$2212,$2213 HCNT
|
||||||
|
mmio.hcnt = 0x0000;
|
||||||
|
|
||||||
|
//$2214,$2215 VCNT
|
||||||
|
mmio.vcnt = 0x0000;
|
||||||
|
|
||||||
|
//$2220-2223 CXB, DXB, EXB, FXB
|
||||||
|
mmio.cbmode = 0;
|
||||||
|
mmio.dbmode = 0;
|
||||||
|
mmio.ebmode = 0;
|
||||||
|
mmio.fbmode = 0;
|
||||||
|
|
||||||
|
mmio.cb = 0x00;
|
||||||
|
mmio.db = 0x01;
|
||||||
|
mmio.eb = 0x02;
|
||||||
|
mmio.fb = 0x03;
|
||||||
|
|
||||||
|
//$2224 BMAPS
|
||||||
|
mmio.sbm = 0x00;
|
||||||
|
|
||||||
|
//$2225 BMAP
|
||||||
|
mmio.sw46 = false;
|
||||||
|
mmio.cbm = 0x00;
|
||||||
|
|
||||||
|
//$2226 SWBE
|
||||||
|
mmio.swen = false;
|
||||||
|
|
||||||
|
//$2227 CWBE
|
||||||
|
mmio.cwen = false;
|
||||||
|
|
||||||
|
//$2228 BWPA
|
||||||
|
mmio.bwp = 0x0f;
|
||||||
|
|
||||||
|
//$2229 SIWP
|
||||||
|
mmio.siwp = 0x00;
|
||||||
|
|
||||||
|
//$222a CIWP
|
||||||
|
mmio.ciwp = 0x00;
|
||||||
|
|
||||||
|
//$2230 DCNT
|
||||||
|
mmio.dmaen = false;
|
||||||
|
mmio.dprio = false;
|
||||||
|
mmio.cden = false;
|
||||||
|
mmio.cdsel = false;
|
||||||
|
mmio.dd = 0;
|
||||||
|
mmio.sd = 0;
|
||||||
|
|
||||||
|
//$2231 CDMA
|
||||||
|
mmio.chdend = false;
|
||||||
|
mmio.dmasize = 0;
|
||||||
|
mmio.dmacb = 0;
|
||||||
|
|
||||||
|
//$2232-$2234 SDA
|
||||||
|
mmio.dsa = 0x000000;
|
||||||
|
|
||||||
|
//$2235-$2237 DDA
|
||||||
|
mmio.dda = 0x000000;
|
||||||
|
|
||||||
|
//$2238,$2239 DTC
|
||||||
|
mmio.dtc = 0x0000;
|
||||||
|
|
||||||
|
//$223f BBF
|
||||||
|
mmio.bbf = 0;
|
||||||
|
|
||||||
|
//$2240-$224f BRF
|
||||||
|
for(unsigned i = 0; i < 16; i++) {
|
||||||
|
mmio.brf[i] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$2250 MCNT
|
||||||
|
mmio.acm = 0;
|
||||||
|
mmio.md = 0;
|
||||||
|
|
||||||
|
//$2251,$2252 MA
|
||||||
|
mmio.ma = 0x0000;
|
||||||
|
|
||||||
|
//$2253,$2254 MB
|
||||||
|
mmio.mb = 0x0000;
|
||||||
|
|
||||||
|
//$2258 VBD
|
||||||
|
mmio.hl = false;
|
||||||
|
mmio.vb = 16;
|
||||||
|
|
||||||
|
//$2259-$225b
|
||||||
|
mmio.va = 0x000000;
|
||||||
|
mmio.vbit = 0;
|
||||||
|
|
||||||
|
//$2300 SFR
|
||||||
|
mmio.cpu_irqfl = false;
|
||||||
|
mmio.chdma_irqfl = false;
|
||||||
|
|
||||||
|
//$2301 CFR
|
||||||
|
mmio.sa1_irqfl = false;
|
||||||
|
mmio.timer_irqfl = false;
|
||||||
|
mmio.dma_irqfl = false;
|
||||||
|
mmio.sa1_nmifl = false;
|
||||||
|
|
||||||
|
//$2302,$2303 HCR
|
||||||
|
mmio.hcr = 0x0000;
|
||||||
|
|
||||||
|
//$2304,$2305 VCR
|
||||||
|
mmio.vcr = 0x0000;
|
||||||
|
|
||||||
|
//$2306-$230a MR
|
||||||
|
mmio.mr = 0;
|
||||||
|
|
||||||
|
//$230b
|
||||||
|
mmio.overflow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SA1::SA1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include "bus/bus.hpp"
|
||||||
|
|
||||||
|
class SA1 : public Coprocessor, public CPUcore, public MMIO {
|
||||||
|
public:
|
||||||
|
#include "dma/dma.hpp"
|
||||||
|
#include "memory/memory.hpp"
|
||||||
|
#include "mmio/mmio.hpp"
|
||||||
|
|
||||||
|
struct Status {
|
||||||
|
uint8 tick_counter;
|
||||||
|
|
||||||
|
bool interrupt_pending;
|
||||||
|
uint16 interrupt_vector;
|
||||||
|
|
||||||
|
uint16 scanlines;
|
||||||
|
uint16 vcounter;
|
||||||
|
uint16 hcounter;
|
||||||
|
} status;
|
||||||
|
|
||||||
|
static void Enter();
|
||||||
|
void enter();
|
||||||
|
void interrupt(uint16 vector);
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
alwaysinline void trigger_irq();
|
||||||
|
alwaysinline void last_cycle();
|
||||||
|
alwaysinline bool interrupt_pending();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
SA1();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SA1 sa1;
|
||||||
|
extern SA1Bus sa1bus;
|
|
@ -0,0 +1,149 @@
|
||||||
|
#ifdef SA1_CPP
|
||||||
|
|
||||||
|
void SA1::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
CPUcore::core_serialize(s);
|
||||||
|
|
||||||
|
//sa1.hpp
|
||||||
|
s.integer(status.tick_counter);
|
||||||
|
|
||||||
|
s.integer(status.interrupt_pending);
|
||||||
|
s.integer(status.interrupt_vector);
|
||||||
|
|
||||||
|
s.integer(status.scanlines);
|
||||||
|
s.integer(status.vcounter);
|
||||||
|
s.integer(status.hcounter);
|
||||||
|
|
||||||
|
//bus/bus.hpp
|
||||||
|
s.array(memory::iram.data(), memory::iram.size());
|
||||||
|
|
||||||
|
s.integer(memory::cc1bwram.dma);
|
||||||
|
|
||||||
|
//dma/dma.hpp
|
||||||
|
s.integer(dma.line);
|
||||||
|
|
||||||
|
//mmio/mmio.hpp
|
||||||
|
s.integer(mmio.sa1_irq);
|
||||||
|
s.integer(mmio.sa1_rdyb);
|
||||||
|
s.integer(mmio.sa1_resb);
|
||||||
|
s.integer(mmio.sa1_nmi);
|
||||||
|
s.integer(mmio.smeg);
|
||||||
|
|
||||||
|
s.integer(mmio.cpu_irqen);
|
||||||
|
s.integer(mmio.chdma_irqen);
|
||||||
|
|
||||||
|
s.integer(mmio.cpu_irqcl);
|
||||||
|
s.integer(mmio.chdma_irqcl);
|
||||||
|
|
||||||
|
s.integer(mmio.crv);
|
||||||
|
|
||||||
|
s.integer(mmio.cnv);
|
||||||
|
|
||||||
|
s.integer(mmio.civ);
|
||||||
|
|
||||||
|
s.integer(mmio.cpu_irq);
|
||||||
|
s.integer(mmio.cpu_ivsw);
|
||||||
|
s.integer(mmio.cpu_nvsw);
|
||||||
|
s.integer(mmio.cmeg);
|
||||||
|
|
||||||
|
s.integer(mmio.sa1_irqen);
|
||||||
|
s.integer(mmio.timer_irqen);
|
||||||
|
s.integer(mmio.dma_irqen);
|
||||||
|
s.integer(mmio.sa1_nmien);
|
||||||
|
|
||||||
|
s.integer(mmio.sa1_irqcl);
|
||||||
|
s.integer(mmio.timer_irqcl);
|
||||||
|
s.integer(mmio.dma_irqcl);
|
||||||
|
s.integer(mmio.sa1_nmicl);
|
||||||
|
|
||||||
|
s.integer(mmio.snv);
|
||||||
|
|
||||||
|
s.integer(mmio.siv);
|
||||||
|
|
||||||
|
s.integer(mmio.hvselb);
|
||||||
|
s.integer(mmio.ven);
|
||||||
|
s.integer(mmio.hen);
|
||||||
|
|
||||||
|
s.integer(mmio.hcnt);
|
||||||
|
|
||||||
|
s.integer(mmio.vcnt);
|
||||||
|
|
||||||
|
s.integer(mmio.cbmode);
|
||||||
|
s.integer(mmio.cb);
|
||||||
|
|
||||||
|
s.integer(mmio.dbmode);
|
||||||
|
s.integer(mmio.db);
|
||||||
|
|
||||||
|
s.integer(mmio.ebmode);
|
||||||
|
s.integer(mmio.eb);
|
||||||
|
|
||||||
|
s.integer(mmio.fbmode);
|
||||||
|
s.integer(mmio.fb);
|
||||||
|
|
||||||
|
s.integer(mmio.sbm);
|
||||||
|
|
||||||
|
s.integer(mmio.sw46);
|
||||||
|
s.integer(mmio.cbm);
|
||||||
|
|
||||||
|
s.integer(mmio.swen);
|
||||||
|
|
||||||
|
s.integer(mmio.cwen);
|
||||||
|
|
||||||
|
s.integer(mmio.bwp);
|
||||||
|
|
||||||
|
s.integer(mmio.siwp);
|
||||||
|
|
||||||
|
s.integer(mmio.ciwp);
|
||||||
|
|
||||||
|
s.integer(mmio.dmaen);
|
||||||
|
s.integer(mmio.dprio);
|
||||||
|
s.integer(mmio.cden);
|
||||||
|
s.integer(mmio.cdsel);
|
||||||
|
s.integer(mmio.dd);
|
||||||
|
s.integer(mmio.sd);
|
||||||
|
|
||||||
|
s.integer(mmio.chdend);
|
||||||
|
s.integer(mmio.dmasize);
|
||||||
|
s.integer(mmio.dmacb);
|
||||||
|
|
||||||
|
s.integer(mmio.dsa);
|
||||||
|
|
||||||
|
s.integer(mmio.dda);
|
||||||
|
|
||||||
|
s.integer(mmio.dtc);
|
||||||
|
|
||||||
|
s.integer(mmio.bbf);
|
||||||
|
|
||||||
|
s.array(mmio.brf);
|
||||||
|
|
||||||
|
s.integer(mmio.acm);
|
||||||
|
s.integer(mmio.md);
|
||||||
|
|
||||||
|
s.integer(mmio.ma);
|
||||||
|
|
||||||
|
s.integer(mmio.mb);
|
||||||
|
|
||||||
|
s.integer(mmio.hl);
|
||||||
|
s.integer(mmio.vb);
|
||||||
|
|
||||||
|
s.integer(mmio.va);
|
||||||
|
s.integer(mmio.vbit);
|
||||||
|
|
||||||
|
s.integer(mmio.cpu_irqfl);
|
||||||
|
s.integer(mmio.chdma_irqfl);
|
||||||
|
|
||||||
|
s.integer(mmio.sa1_irqfl);
|
||||||
|
s.integer(mmio.timer_irqfl);
|
||||||
|
s.integer(mmio.dma_irqfl);
|
||||||
|
s.integer(mmio.sa1_nmifl);
|
||||||
|
|
||||||
|
s.integer(mmio.hcr);
|
||||||
|
|
||||||
|
s.integer(mmio.vcr);
|
||||||
|
|
||||||
|
s.integer(mmio.mr);
|
||||||
|
|
||||||
|
s.integer(mmio.overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,154 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SDD1_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
SDD1 sdd1;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
case 0x4805: return mmc[1] >> 20;
|
||||||
|
case 0x4806: return mmc[2] >> 20;
|
||||||
|
case 0x4807: return mmc[3] >> 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 << 20; break;
|
||||||
|
case 0x4805: mmc[1] = data << 20; break;
|
||||||
|
case 0x4806: mmc[2] = data << 20; break;
|
||||||
|
case 0x4807: mmc[3] = data << 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
SDD1::~SDD1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "sdd1emu.hpp"
|
||||||
|
|
||||||
|
class SDD1 : public MMIO, public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
SDD1();
|
||||||
|
~SDD1();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
|
||||||
|
|
||||||
|
uint8 sdd1_enable; //channel bit-mask
|
||||||
|
uint8 xfer_enable; //channel bit-mask
|
||||||
|
unsigned mmc[4]; //memory map controller ROM indices
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned addr; //$43x2-$43x4 -- DMA transfer address
|
||||||
|
uint16 size; //$43x5-$43x6 -- DMA transfer size
|
||||||
|
} dma[8];
|
||||||
|
|
||||||
|
SDD1emu sdd1emu;
|
||||||
|
struct {
|
||||||
|
uint8 data[65536]; //pointer to decompressed S-DD1 data
|
||||||
|
uint16 offset; //read index into S-DD1 decompression buffer
|
||||||
|
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
|
||||||
|
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()
|
||||||
|
} buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SDD1 sdd1;
|
|
@ -0,0 +1,452 @@
|
||||||
|
#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.
|
||||||
|
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
typedef uint8 bool8;
|
||||||
|
#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
|
|
@ -0,0 +1,164 @@
|
||||||
|
/************************************************************************
|
||||||
|
|
||||||
|
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 bool8 uint8
|
||||||
|
|
||||||
|
class SDD1_IM { //Input Manager
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_IM(void) {}
|
||||||
|
void prepareDecomp(uint32 in_buf);
|
||||||
|
uint8 getCodeword(const uint8 code_len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 byte_ptr;
|
||||||
|
uint8 bit_count;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_GCD { //Golomb-Code Decoder
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_GCD(SDD1_IM *associatedIM);
|
||||||
|
void getRunCount(uint8 code_num, uint8 *MPScount, bool8 *LPSind);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDD1_IM *const IM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_BG { // Bits Generator
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_BG(SDD1_GCD *associatedGCD, uint8 code);
|
||||||
|
void prepareDecomp(void);
|
||||||
|
uint8 getBit(bool8 *endOfRun);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8 code_num;
|
||||||
|
uint8 MPScount;
|
||||||
|
bool8 LPSind;
|
||||||
|
SDD1_GCD *const GCD;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_PEM { //Probability Estimation Module
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
|
||||||
|
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
|
||||||
|
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
|
||||||
|
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
|
||||||
|
void prepareDecomp(void);
|
||||||
|
uint8 getBit(uint8 context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct state {
|
||||||
|
uint8 code_num;
|
||||||
|
uint8 nextIfMPS;
|
||||||
|
uint8 nextIfLPS;
|
||||||
|
};
|
||||||
|
static const state evolution_table[];
|
||||||
|
struct SDD1_ContextInfo {
|
||||||
|
uint8 status;
|
||||||
|
uint8 MPS;
|
||||||
|
} contextInfo[32];
|
||||||
|
SDD1_BG * BG[8];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_CM { //Context Model
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_CM(SDD1_PEM *associatedPEM);
|
||||||
|
void prepareDecomp(uint32 first_byte);
|
||||||
|
uint8 getBit(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 bitplanesInfo;
|
||||||
|
uint8 contextBitsInfo;
|
||||||
|
uint8 bit_number;
|
||||||
|
uint8 currBitplane;
|
||||||
|
uint16 prevBitplaneBits[8];
|
||||||
|
SDD1_PEM *const PEM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1_OL { //Output Logic
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1_OL(SDD1_CM *associatedCM);
|
||||||
|
void prepareDecomp(uint32 first_byte, uint16 out_len, uint8 *out_buf);
|
||||||
|
void launch(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 bitplanesInfo;
|
||||||
|
uint16 length;
|
||||||
|
uint8 *buffer;
|
||||||
|
SDD1_CM *const CM;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
class SDD1emu {
|
||||||
|
|
||||||
|
public:
|
||||||
|
SDD1emu(void);
|
||||||
|
void decompress(uint32 in_buf, uint16 out_len, uint8 *out_buf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDD1_IM IM;
|
||||||
|
SDD1_GCD GCD;
|
||||||
|
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
|
||||||
|
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
|
||||||
|
SDD1_PEM PEM;
|
||||||
|
SDD1_CM CM;
|
||||||
|
SDD1_OL OL;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef bool8
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifdef SDD1_CPP
|
||||||
|
|
||||||
|
void SDD1::serialize(serializer &s) {
|
||||||
|
s.integer(sdd1_enable);
|
||||||
|
s.integer(xfer_enable);
|
||||||
|
s.array(mmc);
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < 8; n++) {
|
||||||
|
s.integer(dma[n].addr);
|
||||||
|
s.integer(dma[n].size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.array(buffer.data);
|
||||||
|
s.integer(buffer.offset);
|
||||||
|
s.integer(buffer.size);
|
||||||
|
s.integer(buffer.ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SERIAL_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
Serial serial;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
static void snesserial_tick(unsigned clocks) { serial.add_clocks(clocks * 8); }
|
||||||
|
static uint8 snesserial_read() { return serial.read(); }
|
||||||
|
static void snesserial_write(uint8 data) { serial.write(data); }
|
||||||
|
|
||||||
|
void Serial::Enter() { serial.enter(); }
|
||||||
|
|
||||||
|
void Serial::enter() {
|
||||||
|
latch = 0;
|
||||||
|
add_clocks(256 * 8); //warm-up
|
||||||
|
if(snesserial_main) snesserial_main(snesserial_tick, snesserial_read, snesserial_write);
|
||||||
|
while(true) add_clocks(frequency); //snesserial_main() fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::add_clocks(unsigned clocks) {
|
||||||
|
step(clocks);
|
||||||
|
synchronize_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Serial::read() {
|
||||||
|
while(cpu.joylatch() == 0) add_clocks(1);
|
||||||
|
while(cpu.joylatch() == 1) add_clocks(1);
|
||||||
|
add_clocks(4);
|
||||||
|
|
||||||
|
uint8 data = 0;
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
add_clocks(8);
|
||||||
|
data = (cpu.joylatch() << 7) | (data >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::write(uint8 data) {
|
||||||
|
latch = 1;
|
||||||
|
add_clocks(8);
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 8; i++) {
|
||||||
|
latch = (data & 1) ^ 1;
|
||||||
|
data >>= 1;
|
||||||
|
add_clocks(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
latch = 0;
|
||||||
|
add_clocks(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Serial::mmio_read(unsigned addr) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
switch(addr & 1) { default:
|
||||||
|
case 0: return r4016->mmio_read(addr);
|
||||||
|
case 1: return r4017->mmio_read(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
switch(addr & 1) { default:
|
||||||
|
case 0: r4016->mmio_write(addr, data); break;
|
||||||
|
case 1: r4017->mmio_write(addr, data); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::enable() {
|
||||||
|
r4016 = memory::mmio.mmio[0x4016 - 0x2000];
|
||||||
|
r4017 = memory::mmio.mmio[0x4017 - 0x2000];
|
||||||
|
memory::mmio.mmio[0x4016 - 0x2000] = this;
|
||||||
|
memory::mmio.mmio[0x4017 - 0x2000] = this;
|
||||||
|
|
||||||
|
if(opened()) close();
|
||||||
|
string name = notdir(cartridge.basename());
|
||||||
|
string path = dir(cartridge.basename());
|
||||||
|
if(open(name, path)) {
|
||||||
|
snesserial_main = sym("snesserial_main");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Serial::reset() {
|
||||||
|
create(Serial::Enter, cartridge.serial_baud_rate() * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
class Serial : public Coprocessor, public MMIO, public library, public property<Serial> {
|
||||||
|
public:
|
||||||
|
static void Enter();
|
||||||
|
void enter();
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
readonly<bool> latch;
|
||||||
|
|
||||||
|
void add_clocks(unsigned clocks);
|
||||||
|
uint8 read();
|
||||||
|
void write(uint8 data);
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MMIO *r4016, *r4017;
|
||||||
|
function<void (void (*)(unsigned), uint8_t (*)(), void (*)(uint8_t))> snesserial_main;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Serial serial;
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifdef SERIAL_CPP
|
||||||
|
|
||||||
|
void Serial::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
s.integer((bool&)latch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,511 @@
|
||||||
|
#ifdef SPC7110_CPP
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::read() {
|
||||||
|
if(decomp_buffer_length == 0) {
|
||||||
|
//decompress at least (decomp_buffer_size / 2) bytes to the buffer
|
||||||
|
switch(decomp_mode) {
|
||||||
|
case 0: mode0(false); break;
|
||||||
|
case 1: mode1(false); break;
|
||||||
|
case 2: mode2(false); break;
|
||||||
|
default: return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 data = decomp_buffer[decomp_buffer_rdoffset++];
|
||||||
|
decomp_buffer_rdoffset &= decomp_buffer_size - 1;
|
||||||
|
decomp_buffer_length--;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::write(uint8 data) {
|
||||||
|
decomp_buffer[decomp_buffer_wroffset++] = data;
|
||||||
|
decomp_buffer_wroffset &= decomp_buffer_size - 1;
|
||||||
|
decomp_buffer_length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::dataread() {
|
||||||
|
unsigned size = memory::cartrom.size() - cartridge.spc7110_data_rom_offset();
|
||||||
|
while(decomp_offset >= size) decomp_offset -= size;
|
||||||
|
return memory::cartrom.read(cartridge.spc7110_data_rom_offset() + decomp_offset++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
||||||
|
decomp_mode = mode;
|
||||||
|
decomp_offset = offset;
|
||||||
|
|
||||||
|
decomp_buffer_rdoffset = 0;
|
||||||
|
decomp_buffer_wroffset = 0;
|
||||||
|
decomp_buffer_length = 0;
|
||||||
|
|
||||||
|
//reset context states
|
||||||
|
for(unsigned i = 0; i < 32; i++) {
|
||||||
|
context[i].index = 0;
|
||||||
|
context[i].invert = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(decomp_mode) {
|
||||||
|
case 0: mode0(true); break;
|
||||||
|
case 1: mode1(true); break;
|
||||||
|
case 2: mode2(true); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//decompress up to requested output data index
|
||||||
|
while(index--) read();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode0(bool init) {
|
||||||
|
static uint8 val, in, span;
|
||||||
|
static int out, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
out = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned bit = 0; bit < 8; bit++) {
|
||||||
|
//get context
|
||||||
|
uint8 mask = (1 << (bit & 3)) - 1;
|
||||||
|
uint8 con = mask + ((inverts & mask) ^ (lps & mask));
|
||||||
|
if(bit > 3) con += 15;
|
||||||
|
|
||||||
|
//get prob and mps
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
unsigned mps = (((out >> 15) & 1) ^ context[con].invert);
|
||||||
|
|
||||||
|
//get bit
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
out = (out << 1) + mps;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
out = (out << 1) + 1 - mps;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
inverts = (inverts << 1) + context[con].invert;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save byte
|
||||||
|
write(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode1(bool init) {
|
||||||
|
static int pixelorder[4], realorder[4];
|
||||||
|
static uint8 in, val, span;
|
||||||
|
static int out, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
for(unsigned i = 0; i < 4; i++) pixelorder[i] = i;
|
||||||
|
out = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned pixel = 0; pixel < 8; pixel++) {
|
||||||
|
//get first symbol context
|
||||||
|
unsigned a = ((out >> (1 * 2)) & 3);
|
||||||
|
unsigned b = ((out >> (7 * 2)) & 3);
|
||||||
|
unsigned c = ((out >> (8 * 2)) & 3);
|
||||||
|
unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
|
||||||
|
|
||||||
|
//update pixel order
|
||||||
|
unsigned m, n;
|
||||||
|
for(m = 0; m < 4; m++) if(pixelorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
|
||||||
|
pixelorder[0] = a;
|
||||||
|
|
||||||
|
//calculate the real pixel order
|
||||||
|
for(m = 0; m < 4; m++) realorder[m] = pixelorder[m];
|
||||||
|
|
||||||
|
//rotate reference pixel c value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == c) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = c;
|
||||||
|
|
||||||
|
//rotate reference pixel b value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == b) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = b;
|
||||||
|
|
||||||
|
//rotate reference pixel a value to top
|
||||||
|
for(m = 0; m < 4; m++) if(realorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = a;
|
||||||
|
|
||||||
|
//get 2 symbols
|
||||||
|
for(unsigned bit = 0; bit < 2; bit++) {
|
||||||
|
//get prob
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
|
||||||
|
//get symbol
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
inverts = (inverts << 1) + context[con].invert;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
|
||||||
|
//get next context
|
||||||
|
con = 5 + (con << 1) + ((lps ^ inverts) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get pixel
|
||||||
|
b = realorder[(lps ^ inverts) & 3];
|
||||||
|
out = (out << 2) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//turn pixel data into bitplanes
|
||||||
|
unsigned data = morton_2x8(out);
|
||||||
|
write(data >> 8);
|
||||||
|
write(data >> 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110Decomp::mode2(bool init) {
|
||||||
|
static int pixelorder[16], realorder[16];
|
||||||
|
static uint8 bitplanebuffer[16], buffer_index;
|
||||||
|
static uint8 in, val, span;
|
||||||
|
static int out0, out1, inverts, lps, in_count;
|
||||||
|
|
||||||
|
if(init == true) {
|
||||||
|
for(unsigned i = 0; i < 16; i++) pixelorder[i] = i;
|
||||||
|
buffer_index = 0;
|
||||||
|
out0 = out1 = inverts = lps = 0;
|
||||||
|
span = 0xff;
|
||||||
|
val = dataread();
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
|
||||||
|
for(unsigned pixel = 0; pixel < 8; pixel++) {
|
||||||
|
//get first symbol context
|
||||||
|
unsigned a = ((out0 >> (0 * 4)) & 15);
|
||||||
|
unsigned b = ((out0 >> (7 * 4)) & 15);
|
||||||
|
unsigned c = ((out1 >> (0 * 4)) & 15);
|
||||||
|
unsigned con = 0;
|
||||||
|
unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
|
||||||
|
|
||||||
|
//update pixel order
|
||||||
|
unsigned m, n;
|
||||||
|
for(m = 0; m < 16; m++) if(pixelorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
|
||||||
|
pixelorder[0] = a;
|
||||||
|
|
||||||
|
//calculate the real pixel order
|
||||||
|
for(m = 0; m < 16; m++) realorder[m] = pixelorder[m];
|
||||||
|
|
||||||
|
//rotate reference pixel c value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == c) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = c;
|
||||||
|
|
||||||
|
//rotate reference pixel b value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == b) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = b;
|
||||||
|
|
||||||
|
//rotate reference pixel a value to top
|
||||||
|
for(m = 0; m < 16; m++) if(realorder[m] == a) break;
|
||||||
|
for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
|
||||||
|
realorder[0] = a;
|
||||||
|
|
||||||
|
//get 4 symbols
|
||||||
|
for(unsigned bit = 0; bit < 4; bit++) {
|
||||||
|
//get prob
|
||||||
|
unsigned prob = probability(con);
|
||||||
|
|
||||||
|
//get symbol
|
||||||
|
unsigned flag_lps;
|
||||||
|
if(val <= span - prob) { //mps
|
||||||
|
span = span - prob;
|
||||||
|
flag_lps = 0;
|
||||||
|
} else { //lps
|
||||||
|
val = val - (span - (prob - 1));
|
||||||
|
span = prob - 1;
|
||||||
|
flag_lps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//renormalize
|
||||||
|
unsigned shift = 0;
|
||||||
|
while(span < 0x7f) {
|
||||||
|
shift++;
|
||||||
|
|
||||||
|
span = (span << 1) + 1;
|
||||||
|
val = (val << 1) + (in >> 7);
|
||||||
|
|
||||||
|
in <<= 1;
|
||||||
|
if(--in_count == 0) {
|
||||||
|
in = dataread();
|
||||||
|
in_count = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update processing info
|
||||||
|
lps = (lps << 1) + flag_lps;
|
||||||
|
unsigned invertbit = context[con].invert;
|
||||||
|
inverts = (inverts << 1) + invertbit;
|
||||||
|
|
||||||
|
//update context state
|
||||||
|
if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
|
||||||
|
if(flag_lps) context[con].index = next_lps(con);
|
||||||
|
else if(shift) context[con].index = next_mps(con);
|
||||||
|
|
||||||
|
//get next context
|
||||||
|
con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get pixel
|
||||||
|
b = realorder[(lps ^ inverts) & 0x0f];
|
||||||
|
out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
|
||||||
|
out0 = (out0 << 4) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert pixel data into bitplanes
|
||||||
|
unsigned data = morton_4x8(out0);
|
||||||
|
write(data >> 24);
|
||||||
|
write(data >> 16);
|
||||||
|
bitplanebuffer[buffer_index++] = data >> 8;
|
||||||
|
bitplanebuffer[buffer_index++] = data >> 0;
|
||||||
|
|
||||||
|
if(buffer_index == 16) {
|
||||||
|
for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]);
|
||||||
|
buffer_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
const uint8 SPC7110Decomp::evolution_table[53][4] = {
|
||||||
|
//{ prob, nextlps, nextmps, toggle invert },
|
||||||
|
|
||||||
|
{ 0x5a, 1, 1, 1 },
|
||||||
|
{ 0x25, 6, 2, 0 },
|
||||||
|
{ 0x11, 8, 3, 0 },
|
||||||
|
{ 0x08, 10, 4, 0 },
|
||||||
|
{ 0x03, 12, 5, 0 },
|
||||||
|
{ 0x01, 15, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x5a, 7, 7, 1 },
|
||||||
|
{ 0x3f, 19, 8, 0 },
|
||||||
|
{ 0x2c, 21, 9, 0 },
|
||||||
|
{ 0x20, 22, 10, 0 },
|
||||||
|
{ 0x17, 23, 11, 0 },
|
||||||
|
{ 0x11, 25, 12, 0 },
|
||||||
|
{ 0x0c, 26, 13, 0 },
|
||||||
|
{ 0x09, 28, 14, 0 },
|
||||||
|
{ 0x07, 29, 15, 0 },
|
||||||
|
{ 0x05, 31, 16, 0 },
|
||||||
|
{ 0x04, 32, 17, 0 },
|
||||||
|
{ 0x03, 34, 18, 0 },
|
||||||
|
{ 0x02, 35, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x5a, 20, 20, 1 },
|
||||||
|
{ 0x48, 39, 21, 0 },
|
||||||
|
{ 0x3a, 40, 22, 0 },
|
||||||
|
{ 0x2e, 42, 23, 0 },
|
||||||
|
{ 0x26, 44, 24, 0 },
|
||||||
|
{ 0x1f, 45, 25, 0 },
|
||||||
|
{ 0x19, 46, 26, 0 },
|
||||||
|
{ 0x15, 25, 27, 0 },
|
||||||
|
{ 0x11, 26, 28, 0 },
|
||||||
|
{ 0x0e, 26, 29, 0 },
|
||||||
|
{ 0x0b, 27, 30, 0 },
|
||||||
|
{ 0x09, 28, 31, 0 },
|
||||||
|
{ 0x08, 29, 32, 0 },
|
||||||
|
{ 0x07, 30, 33, 0 },
|
||||||
|
{ 0x05, 31, 34, 0 },
|
||||||
|
{ 0x04, 33, 35, 0 },
|
||||||
|
{ 0x04, 33, 36, 0 },
|
||||||
|
{ 0x03, 34, 37, 0 },
|
||||||
|
{ 0x02, 35, 38, 0 },
|
||||||
|
{ 0x02, 36, 5, 0 },
|
||||||
|
|
||||||
|
{ 0x58, 39, 40, 1 },
|
||||||
|
{ 0x4d, 47, 41, 0 },
|
||||||
|
{ 0x43, 48, 42, 0 },
|
||||||
|
{ 0x3b, 49, 43, 0 },
|
||||||
|
{ 0x34, 50, 44, 0 },
|
||||||
|
{ 0x2e, 51, 45, 0 },
|
||||||
|
{ 0x29, 44, 46, 0 },
|
||||||
|
{ 0x25, 45, 24, 0 },
|
||||||
|
|
||||||
|
{ 0x56, 47, 48, 1 },
|
||||||
|
{ 0x4f, 47, 49, 0 },
|
||||||
|
{ 0x47, 48, 50, 0 },
|
||||||
|
{ 0x41, 49, 51, 0 },
|
||||||
|
{ 0x3c, 50, 52, 0 },
|
||||||
|
{ 0x37, 51, 43, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8 SPC7110Decomp::mode2_context_table[32][2] = {
|
||||||
|
//{ next 0, next 1 },
|
||||||
|
|
||||||
|
{ 1, 2 },
|
||||||
|
|
||||||
|
{ 3, 8 },
|
||||||
|
{ 13, 14 },
|
||||||
|
|
||||||
|
{ 15, 16 },
|
||||||
|
{ 17, 18 },
|
||||||
|
{ 19, 20 },
|
||||||
|
{ 21, 22 },
|
||||||
|
{ 23, 24 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 25, 26 },
|
||||||
|
{ 27, 28 },
|
||||||
|
{ 29, 30 },
|
||||||
|
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
{ 31, 31 },
|
||||||
|
|
||||||
|
{ 31, 31 },
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 SPC7110Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; }
|
||||||
|
uint8 SPC7110Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; }
|
||||||
|
uint8 SPC7110Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; }
|
||||||
|
bool SPC7110Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; }
|
||||||
|
|
||||||
|
unsigned SPC7110Decomp::morton_2x8(unsigned data) {
|
||||||
|
//reverse morton lookup: de-interleave two 8-bit values
|
||||||
|
//15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8
|
||||||
|
//14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0
|
||||||
|
return morton16[0][(data >> 0) & 255] + morton16[1][(data >> 8) & 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110Decomp::morton_4x8(unsigned data) {
|
||||||
|
//reverse morton lookup: de-interleave four 8-bit values
|
||||||
|
//31, 27, 23, 19, 15, 11, 7, 3 -> 31-24
|
||||||
|
//30, 26, 22, 18, 14, 10, 6, 2 -> 23-16
|
||||||
|
//29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8
|
||||||
|
//28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0
|
||||||
|
return morton32[0][(data >> 0) & 255] + morton32[1][(data >> 8) & 255]
|
||||||
|
+ morton32[2][(data >> 16) & 255] + morton32[3][(data >> 24) & 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SPC7110Decomp::reset() {
|
||||||
|
//mode 3 is invalid; this is treated as a special case to always return 0x00
|
||||||
|
//set to mode 3 so that reading decomp port before starting first decomp will return 0x00
|
||||||
|
decomp_mode = 3;
|
||||||
|
|
||||||
|
decomp_buffer_rdoffset = 0;
|
||||||
|
decomp_buffer_wroffset = 0;
|
||||||
|
decomp_buffer_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110Decomp::SPC7110Decomp() {
|
||||||
|
decomp_buffer = new uint8_t[decomp_buffer_size];
|
||||||
|
reset();
|
||||||
|
|
||||||
|
//initialize reverse morton lookup tables
|
||||||
|
for(unsigned i = 0; i < 256; i++) {
|
||||||
|
#define map(x, y) (((i >> x) & 1) << y)
|
||||||
|
//2x8-bit
|
||||||
|
morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6)
|
||||||
|
+ map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
|
||||||
|
morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2)
|
||||||
|
+ map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
|
||||||
|
//4x8-bit
|
||||||
|
morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7)
|
||||||
|
+ map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
|
||||||
|
morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5)
|
||||||
|
+ map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
|
||||||
|
morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3)
|
||||||
|
+ map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
|
||||||
|
morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1)
|
||||||
|
+ map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
|
||||||
|
#undef map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110Decomp::~SPC7110Decomp() {
|
||||||
|
delete[] decomp_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
class SPC7110Decomp {
|
||||||
|
public:
|
||||||
|
uint8 read();
|
||||||
|
void init(unsigned mode, unsigned offset, unsigned index);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
SPC7110Decomp();
|
||||||
|
~SPC7110Decomp();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned decomp_mode;
|
||||||
|
unsigned decomp_offset;
|
||||||
|
|
||||||
|
//read() will spool chunks half the size of decomp_buffer_size
|
||||||
|
enum { decomp_buffer_size = 64 }; //must be >= 64, and must be a power of two
|
||||||
|
uint8 *decomp_buffer;
|
||||||
|
unsigned decomp_buffer_rdoffset;
|
||||||
|
unsigned decomp_buffer_wroffset;
|
||||||
|
unsigned decomp_buffer_length;
|
||||||
|
|
||||||
|
void write(uint8 data);
|
||||||
|
uint8 dataread();
|
||||||
|
|
||||||
|
void mode0(bool init);
|
||||||
|
void mode1(bool init);
|
||||||
|
void mode2(bool init);
|
||||||
|
|
||||||
|
static const uint8 evolution_table[53][4];
|
||||||
|
static const uint8 mode2_context_table[32][2];
|
||||||
|
|
||||||
|
struct ContextState {
|
||||||
|
uint8 index;
|
||||||
|
uint8 invert;
|
||||||
|
} context[32];
|
||||||
|
|
||||||
|
uint8 probability(unsigned n);
|
||||||
|
uint8 next_lps(unsigned n);
|
||||||
|
uint8 next_mps(unsigned n);
|
||||||
|
bool toggle_invert(unsigned n);
|
||||||
|
|
||||||
|
unsigned morton16[2][256];
|
||||||
|
unsigned morton32[4][256];
|
||||||
|
unsigned morton_2x8(unsigned data);
|
||||||
|
unsigned morton_4x8(unsigned data);
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
#ifdef SPC7110_CPP
|
||||||
|
|
||||||
|
void SPC7110Decomp::serialize(serializer &s) {
|
||||||
|
s.integer(decomp_mode);
|
||||||
|
s.integer(decomp_offset);
|
||||||
|
|
||||||
|
s.array(decomp_buffer, decomp_buffer_size);
|
||||||
|
s.integer(decomp_buffer_rdoffset);
|
||||||
|
s.integer(decomp_buffer_wroffset);
|
||||||
|
s.integer(decomp_buffer_length);
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < 32; n++) {
|
||||||
|
s.integer(context[n].index);
|
||||||
|
s.integer(context[n].invert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::serialize(serializer &s) {
|
||||||
|
s.integer(r4801);
|
||||||
|
s.integer(r4802);
|
||||||
|
s.integer(r4803);
|
||||||
|
s.integer(r4804);
|
||||||
|
s.integer(r4805);
|
||||||
|
s.integer(r4806);
|
||||||
|
s.integer(r4807);
|
||||||
|
s.integer(r4808);
|
||||||
|
s.integer(r4809);
|
||||||
|
s.integer(r480a);
|
||||||
|
s.integer(r480b);
|
||||||
|
s.integer(r480c);
|
||||||
|
decomp.serialize(s);
|
||||||
|
|
||||||
|
s.integer(r4811);
|
||||||
|
s.integer(r4812);
|
||||||
|
s.integer(r4813);
|
||||||
|
s.integer(r4814);
|
||||||
|
s.integer(r4815);
|
||||||
|
s.integer(r4816);
|
||||||
|
s.integer(r4817);
|
||||||
|
s.integer(r4818);
|
||||||
|
s.integer(r481x);
|
||||||
|
s.integer(r4814_latch);
|
||||||
|
s.integer(r4815_latch);
|
||||||
|
|
||||||
|
s.integer(r4820);
|
||||||
|
s.integer(r4821);
|
||||||
|
s.integer(r4822);
|
||||||
|
s.integer(r4823);
|
||||||
|
s.integer(r4824);
|
||||||
|
s.integer(r4825);
|
||||||
|
s.integer(r4826);
|
||||||
|
s.integer(r4827);
|
||||||
|
s.integer(r4828);
|
||||||
|
s.integer(r4829);
|
||||||
|
s.integer(r482a);
|
||||||
|
s.integer(r482b);
|
||||||
|
s.integer(r482c);
|
||||||
|
s.integer(r482d);
|
||||||
|
s.integer(r482e);
|
||||||
|
s.integer(r482f);
|
||||||
|
|
||||||
|
s.integer(r4830);
|
||||||
|
s.integer(r4831);
|
||||||
|
s.integer(r4832);
|
||||||
|
s.integer(r4833);
|
||||||
|
s.integer(r4834);
|
||||||
|
|
||||||
|
s.integer(dx_offset);
|
||||||
|
s.integer(ex_offset);
|
||||||
|
s.integer(fx_offset);
|
||||||
|
|
||||||
|
s.integer(r4840);
|
||||||
|
s.integer(r4841);
|
||||||
|
s.integer(r4842);
|
||||||
|
|
||||||
|
s.integer(rtc_state);
|
||||||
|
s.integer(rtc_mode);
|
||||||
|
s.integer(rtc_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,682 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SPC7110_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
SPC7110 spc7110;
|
||||||
|
SPC7110MCU spc7110mcu;
|
||||||
|
SPC7110DCU spc7110dcu;
|
||||||
|
SPC7110RAM spc7110ram;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#include "decomp.cpp"
|
||||||
|
|
||||||
|
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
void SPC7110::init() {}
|
||||||
|
void SPC7110::enable() {}
|
||||||
|
|
||||||
|
void SPC7110::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::reset() {
|
||||||
|
r4801 = 0x00;
|
||||||
|
r4802 = 0x00;
|
||||||
|
r4803 = 0x00;
|
||||||
|
r4804 = 0x00;
|
||||||
|
r4805 = 0x00;
|
||||||
|
r4806 = 0x00;
|
||||||
|
r4807 = 0x00;
|
||||||
|
r4808 = 0x00;
|
||||||
|
r4809 = 0x00;
|
||||||
|
r480a = 0x00;
|
||||||
|
r480b = 0x00;
|
||||||
|
r480c = 0x00;
|
||||||
|
|
||||||
|
decomp.reset();
|
||||||
|
|
||||||
|
r4811 = 0x00;
|
||||||
|
r4812 = 0x00;
|
||||||
|
r4813 = 0x00;
|
||||||
|
r4814 = 0x00;
|
||||||
|
r4815 = 0x00;
|
||||||
|
r4816 = 0x00;
|
||||||
|
r4817 = 0x00;
|
||||||
|
r4818 = 0x00;
|
||||||
|
|
||||||
|
r481x = 0x00;
|
||||||
|
r4814_latch = false;
|
||||||
|
r4815_latch = false;
|
||||||
|
|
||||||
|
r4820 = 0x00;
|
||||||
|
r4821 = 0x00;
|
||||||
|
r4822 = 0x00;
|
||||||
|
r4823 = 0x00;
|
||||||
|
r4824 = 0x00;
|
||||||
|
r4825 = 0x00;
|
||||||
|
r4826 = 0x00;
|
||||||
|
r4827 = 0x00;
|
||||||
|
r4828 = 0x00;
|
||||||
|
r4829 = 0x00;
|
||||||
|
r482a = 0x00;
|
||||||
|
r482b = 0x00;
|
||||||
|
r482c = 0x00;
|
||||||
|
r482d = 0x00;
|
||||||
|
r482e = 0x00;
|
||||||
|
r482f = 0x00;
|
||||||
|
|
||||||
|
r4830 = 0x00;
|
||||||
|
mmio_write(0x4831, 0);
|
||||||
|
mmio_write(0x4832, 1);
|
||||||
|
mmio_write(0x4833, 2);
|
||||||
|
r4834 = 0x00;
|
||||||
|
|
||||||
|
r4840 = 0x00;
|
||||||
|
r4841 = 0x00;
|
||||||
|
r4842 = 0x00;
|
||||||
|
|
||||||
|
if(cartridge.has_spc7110rtc()) {
|
||||||
|
rtc_state = RTCS_Inactive;
|
||||||
|
rtc_mode = RTCM_Linear;
|
||||||
|
rtc_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110::datarom_addr(unsigned addr) {
|
||||||
|
unsigned size = memory::cartrom.size() - cartridge.spc7110_data_rom_offset();
|
||||||
|
while(addr >= size) addr -= size;
|
||||||
|
return cartridge.spc7110_data_rom_offset() + addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
|
||||||
|
unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); }
|
||||||
|
unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); }
|
||||||
|
void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
|
||||||
|
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
|
||||||
|
|
||||||
|
void SPC7110::update_time(int offset) {
|
||||||
|
time_t rtc_time
|
||||||
|
= (memory::cartrtc.read(16) << 0)
|
||||||
|
| (memory::cartrtc.read(17) << 8)
|
||||||
|
| (memory::cartrtc.read(18) << 16)
|
||||||
|
| (memory::cartrtc.read(19) << 24);
|
||||||
|
time_t current_time = time(0) - offset;
|
||||||
|
|
||||||
|
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||||
|
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||||
|
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||||
|
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||||
|
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||||
|
//or whether time_t is signed or unsigned.
|
||||||
|
time_t diff
|
||||||
|
= (current_time >= rtc_time)
|
||||||
|
? (current_time - rtc_time)
|
||||||
|
: (std::numeric_limits<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
|
||||||
|
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||||
|
|
||||||
|
bool update = true;
|
||||||
|
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
|
||||||
|
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
|
||||||
|
|
||||||
|
if(diff > 0 && update == true) {
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||||
|
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
|
||||||
|
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
|
||||||
|
unsigned weekday = memory::cartrtc.read(12);
|
||||||
|
|
||||||
|
day--;
|
||||||
|
month--;
|
||||||
|
year += (year >= 90) ? 1900 : 2000; //range = 1990-2089
|
||||||
|
|
||||||
|
second += diff;
|
||||||
|
while(second >= 60) {
|
||||||
|
second -= 60;
|
||||||
|
|
||||||
|
minute++;
|
||||||
|
if(minute < 60) continue;
|
||||||
|
minute = 0;
|
||||||
|
|
||||||
|
hour++;
|
||||||
|
if(hour < 24) continue;
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
day++;
|
||||||
|
weekday = (weekday + 1) % 7;
|
||||||
|
unsigned days = months[month % 12];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((year % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
if(day < days) continue;
|
||||||
|
day = 0;
|
||||||
|
|
||||||
|
month++;
|
||||||
|
if(month < 12) continue;
|
||||||
|
month = 0;
|
||||||
|
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
day++;
|
||||||
|
month++;
|
||||||
|
year %= 100;
|
||||||
|
|
||||||
|
memory::cartrtc.write( 0, second % 10);
|
||||||
|
memory::cartrtc.write( 1, second / 10);
|
||||||
|
memory::cartrtc.write( 2, minute % 10);
|
||||||
|
memory::cartrtc.write( 3, minute / 10);
|
||||||
|
memory::cartrtc.write( 4, hour % 10);
|
||||||
|
memory::cartrtc.write( 5, hour / 10);
|
||||||
|
memory::cartrtc.write( 6, day % 10);
|
||||||
|
memory::cartrtc.write( 7, day / 10);
|
||||||
|
memory::cartrtc.write( 8, month % 10);
|
||||||
|
memory::cartrtc.write( 9, month / 10);
|
||||||
|
memory::cartrtc.write(10, year % 10);
|
||||||
|
memory::cartrtc.write(11, (year / 10) % 10);
|
||||||
|
memory::cartrtc.write(12, weekday % 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(16, current_time >> 0);
|
||||||
|
memory::cartrtc.write(17, current_time >> 8);
|
||||||
|
memory::cartrtc.write(18, current_time >> 16);
|
||||||
|
memory::cartrtc.write(19, current_time >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case 0x4800: {
|
||||||
|
uint16 counter = (r4809 + (r480a << 8));
|
||||||
|
counter--;
|
||||||
|
r4809 = counter;
|
||||||
|
r480a = counter >> 8;
|
||||||
|
return decomp.read();
|
||||||
|
}
|
||||||
|
case 0x4801: return r4801;
|
||||||
|
case 0x4802: return r4802;
|
||||||
|
case 0x4803: return r4803;
|
||||||
|
case 0x4804: return r4804;
|
||||||
|
case 0x4805: return r4805;
|
||||||
|
case 0x4806: return r4806;
|
||||||
|
case 0x4807: return r4807;
|
||||||
|
case 0x4808: return r4808;
|
||||||
|
case 0x4809: return r4809;
|
||||||
|
case 0x480a: return r480a;
|
||||||
|
case 0x480b: return r480b;
|
||||||
|
case 0x480c: {
|
||||||
|
uint8 status = r480c;
|
||||||
|
r480c &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
|
||||||
|
case 0x4810: {
|
||||||
|
if(r481x != 0x07) return 0x00;
|
||||||
|
|
||||||
|
unsigned addr = data_pointer();
|
||||||
|
unsigned adjust = data_adjust();
|
||||||
|
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||||
|
|
||||||
|
unsigned adjustaddr = addr;
|
||||||
|
if(r4818 & 2) {
|
||||||
|
adjustaddr += adjust;
|
||||||
|
set_data_adjust(adjust + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
|
||||||
|
if(!(r4818 & 2)) {
|
||||||
|
unsigned increment = (r4818 & 1) ? data_increment() : 1;
|
||||||
|
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
|
||||||
|
|
||||||
|
if((r4818 & 16) == 0) {
|
||||||
|
set_data_pointer(addr + increment);
|
||||||
|
} else {
|
||||||
|
set_data_adjust(adjust + increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
case 0x4811: return r4811;
|
||||||
|
case 0x4812: return r4812;
|
||||||
|
case 0x4813: return r4813;
|
||||||
|
case 0x4814: return r4814;
|
||||||
|
case 0x4815: return r4815;
|
||||||
|
case 0x4816: return r4816;
|
||||||
|
case 0x4817: return r4817;
|
||||||
|
case 0x4818: return r4818;
|
||||||
|
case 0x481a: {
|
||||||
|
if(r481x != 0x07) return 0x00;
|
||||||
|
|
||||||
|
unsigned addr = data_pointer();
|
||||||
|
unsigned adjust = data_adjust();
|
||||||
|
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||||
|
|
||||||
|
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
|
||||||
|
if((r4818 & 0x60) == 0x60) {
|
||||||
|
if((r4818 & 16) == 0) {
|
||||||
|
set_data_pointer(addr + adjust);
|
||||||
|
} else {
|
||||||
|
set_data_adjust(adjust + adjust);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
|
||||||
|
case 0x4820: return r4820;
|
||||||
|
case 0x4821: return r4821;
|
||||||
|
case 0x4822: return r4822;
|
||||||
|
case 0x4823: return r4823;
|
||||||
|
case 0x4824: return r4824;
|
||||||
|
case 0x4825: return r4825;
|
||||||
|
case 0x4826: return r4826;
|
||||||
|
case 0x4827: return r4827;
|
||||||
|
case 0x4828: return r4828;
|
||||||
|
case 0x4829: return r4829;
|
||||||
|
case 0x482a: return r482a;
|
||||||
|
case 0x482b: return r482b;
|
||||||
|
case 0x482c: return r482c;
|
||||||
|
case 0x482d: return r482d;
|
||||||
|
case 0x482e: return r482e;
|
||||||
|
case 0x482f: {
|
||||||
|
uint8 status = r482f;
|
||||||
|
r482f &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
|
||||||
|
case 0x4830: return r4830;
|
||||||
|
case 0x4831: return r4831;
|
||||||
|
case 0x4832: return r4832;
|
||||||
|
case 0x4833: return r4833;
|
||||||
|
case 0x4834: return r4834;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
|
||||||
|
case 0x4840: return r4840;
|
||||||
|
case 0x4841: {
|
||||||
|
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
|
||||||
|
|
||||||
|
r4842 = 0x80;
|
||||||
|
uint8 data = memory::cartrtc.read(rtc_index);
|
||||||
|
rtc_index = (rtc_index + 1) & 15;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
case 0x4842: {
|
||||||
|
uint8 status = r4842;
|
||||||
|
r4842 &= 0x7f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
switch(addr) {
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case 0x4801: r4801 = data; break;
|
||||||
|
case 0x4802: r4802 = data; break;
|
||||||
|
case 0x4803: r4803 = data; break;
|
||||||
|
case 0x4804: r4804 = data; break;
|
||||||
|
case 0x4805: r4805 = data; break;
|
||||||
|
case 0x4806: {
|
||||||
|
r4806 = data;
|
||||||
|
|
||||||
|
unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16));
|
||||||
|
unsigned index = (r4804 << 2);
|
||||||
|
unsigned length = (r4809 + (r480a << 8));
|
||||||
|
unsigned addr = datarom_addr(table + index);
|
||||||
|
unsigned mode = (memory::cartrom.read(addr + 0));
|
||||||
|
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
|
||||||
|
+ (memory::cartrom.read(addr + 2) << 8)
|
||||||
|
+ (memory::cartrom.read(addr + 3) << 0);
|
||||||
|
|
||||||
|
decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode);
|
||||||
|
r480c = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4807: r4807 = data; break;
|
||||||
|
case 0x4808: r4808 = data; break;
|
||||||
|
case 0x4809: r4809 = data; break;
|
||||||
|
case 0x480a: r480a = data; break;
|
||||||
|
case 0x480b: r480b = data; break;
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
|
||||||
|
case 0x4811: r4811 = data; r481x |= 0x01; break;
|
||||||
|
case 0x4812: r4812 = data; r481x |= 0x02; break;
|
||||||
|
case 0x4813: r4813 = data; r481x |= 0x04; break;
|
||||||
|
case 0x4814: {
|
||||||
|
r4814 = data;
|
||||||
|
r4814_latch = true;
|
||||||
|
if(!r4815_latch) break;
|
||||||
|
if(!(r4818 & 2)) break;
|
||||||
|
if(r4818 & 0x10) break;
|
||||||
|
|
||||||
|
if((r4818 & 0x60) == 0x20) {
|
||||||
|
unsigned increment = data_adjust() & 0xff;
|
||||||
|
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
} else if((r4818 & 0x60) == 0x40) {
|
||||||
|
unsigned increment = data_adjust();
|
||||||
|
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case 0x4815: {
|
||||||
|
r4815 = data;
|
||||||
|
r4815_latch = true;
|
||||||
|
if(!r4814_latch) break;
|
||||||
|
if(!(r4818 & 2)) break;
|
||||||
|
if(r4818 & 0x10) break;
|
||||||
|
|
||||||
|
if((r4818 & 0x60) == 0x20) {
|
||||||
|
unsigned increment = data_adjust() & 0xff;
|
||||||
|
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
} else if((r4818 & 0x60) == 0x40) {
|
||||||
|
unsigned increment = data_adjust();
|
||||||
|
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||||
|
set_data_pointer(data_pointer() + increment);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case 0x4816: r4816 = data; break;
|
||||||
|
case 0x4817: r4817 = data; break;
|
||||||
|
case 0x4818: {
|
||||||
|
if(r481x != 0x07) break;
|
||||||
|
|
||||||
|
r4818 = data;
|
||||||
|
r4814_latch = r4815_latch = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
|
||||||
|
case 0x4820: r4820 = data; break;
|
||||||
|
case 0x4821: r4821 = data; break;
|
||||||
|
case 0x4822: r4822 = data; break;
|
||||||
|
case 0x4823: r4823 = data; break;
|
||||||
|
case 0x4824: r4824 = data; break;
|
||||||
|
case 0x4825: {
|
||||||
|
r4825 = data;
|
||||||
|
|
||||||
|
if(r482e & 1) {
|
||||||
|
//signed 16-bit x 16-bit multiplication
|
||||||
|
int16 r0 = (int16)(r4824 + (r4825 << 8));
|
||||||
|
int16 r1 = (int16)(r4820 + (r4821 << 8));
|
||||||
|
|
||||||
|
signed result = r0 * r1;
|
||||||
|
r4828 = result;
|
||||||
|
r4829 = result >> 8;
|
||||||
|
r482a = result >> 16;
|
||||||
|
r482b = result >> 24;
|
||||||
|
} else {
|
||||||
|
//unsigned 16-bit x 16-bit multiplication
|
||||||
|
uint16 r0 = (uint16)(r4824 + (r4825 << 8));
|
||||||
|
uint16 r1 = (uint16)(r4820 + (r4821 << 8));
|
||||||
|
|
||||||
|
unsigned result = r0 * r1;
|
||||||
|
r4828 = result;
|
||||||
|
r4829 = result >> 8;
|
||||||
|
r482a = result >> 16;
|
||||||
|
r482b = result >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
r482f = 0x80;
|
||||||
|
} break;
|
||||||
|
case 0x4826: r4826 = data; break;
|
||||||
|
case 0x4827: {
|
||||||
|
r4827 = data;
|
||||||
|
|
||||||
|
if(r482e & 1) {
|
||||||
|
//signed 32-bit x 16-bit division
|
||||||
|
int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||||
|
int16 divisor = (int16)(r4826 + (r4827 << 8));
|
||||||
|
|
||||||
|
int32 quotient;
|
||||||
|
int16 remainder;
|
||||||
|
|
||||||
|
if(divisor) {
|
||||||
|
quotient = (int32)(dividend / divisor);
|
||||||
|
remainder = (int32)(dividend % divisor);
|
||||||
|
} else {
|
||||||
|
//illegal division by zero
|
||||||
|
quotient = 0;
|
||||||
|
remainder = dividend & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
r4828 = quotient;
|
||||||
|
r4829 = quotient >> 8;
|
||||||
|
r482a = quotient >> 16;
|
||||||
|
r482b = quotient >> 24;
|
||||||
|
|
||||||
|
r482c = remainder;
|
||||||
|
r482d = remainder >> 8;
|
||||||
|
} else {
|
||||||
|
//unsigned 32-bit x 16-bit division
|
||||||
|
uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||||
|
uint16 divisor = (uint16)(r4826 + (r4827 << 8));
|
||||||
|
|
||||||
|
uint32 quotient;
|
||||||
|
uint16 remainder;
|
||||||
|
|
||||||
|
if(divisor) {
|
||||||
|
quotient = (uint32)(dividend / divisor);
|
||||||
|
remainder = (uint16)(dividend % divisor);
|
||||||
|
} else {
|
||||||
|
//illegal division by zero
|
||||||
|
quotient = 0;
|
||||||
|
remainder = dividend & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
r4828 = quotient;
|
||||||
|
r4829 = quotient >> 8;
|
||||||
|
r482a = quotient >> 16;
|
||||||
|
r482b = quotient >> 24;
|
||||||
|
|
||||||
|
r482c = remainder;
|
||||||
|
r482d = remainder >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r482f = 0x80;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x482e: {
|
||||||
|
//reset math unit
|
||||||
|
r4820 = r4821 = r4822 = r4823 = 0;
|
||||||
|
r4824 = r4825 = r4826 = r4827 = 0;
|
||||||
|
r4828 = r4829 = r482a = r482b = 0;
|
||||||
|
r482c = r482d = 0;
|
||||||
|
|
||||||
|
r482e = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
|
||||||
|
case 0x4830: r4830 = data; break;
|
||||||
|
|
||||||
|
case 0x4831: {
|
||||||
|
r4831 = data;
|
||||||
|
dx_offset = datarom_addr(data * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4832: {
|
||||||
|
r4832 = data;
|
||||||
|
ex_offset = datarom_addr(data * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4833: {
|
||||||
|
r4833 = data;
|
||||||
|
fx_offset = datarom_addr(data * 0x100000);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4834: r4834 = data; break;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
|
||||||
|
case 0x4840: {
|
||||||
|
r4840 = data;
|
||||||
|
if(!(r4840 & 1)) {
|
||||||
|
//disable RTC
|
||||||
|
rtc_state = RTCS_Inactive;
|
||||||
|
update_time();
|
||||||
|
} else {
|
||||||
|
//enable RTC
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_state = RTCS_ModeSelect;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x4841: {
|
||||||
|
r4841 = data;
|
||||||
|
|
||||||
|
switch(rtc_state) {
|
||||||
|
case RTCS_ModeSelect: {
|
||||||
|
if(data == RTCM_Linear || data == RTCM_Indexed) {
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_state = RTCS_IndexSelect;
|
||||||
|
rtc_mode = (RTC_Mode)data;
|
||||||
|
rtc_index = 0;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RTCS_IndexSelect: {
|
||||||
|
r4842 = 0x80;
|
||||||
|
rtc_index = data & 15;
|
||||||
|
if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RTCS_Write: {
|
||||||
|
r4842 = 0x80;
|
||||||
|
|
||||||
|
//control register 0
|
||||||
|
if(rtc_index == 13) {
|
||||||
|
//increment second counter
|
||||||
|
if(data & 2) update_time(+1);
|
||||||
|
|
||||||
|
//round minute counter
|
||||||
|
if(data & 8) {
|
||||||
|
update_time();
|
||||||
|
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
//clear seconds
|
||||||
|
memory::cartrtc.write(0, 0);
|
||||||
|
memory::cartrtc.write(1, 0);
|
||||||
|
|
||||||
|
if(second >= 30) update_time(+60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//control register 2
|
||||||
|
if(rtc_index == 15) {
|
||||||
|
//disable timer and clear second counter
|
||||||
|
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
|
||||||
|
update_time();
|
||||||
|
|
||||||
|
//clear seconds
|
||||||
|
memory::cartrtc.write(0, 0);
|
||||||
|
memory::cartrtc.write(1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//disable timer
|
||||||
|
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
|
||||||
|
update_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(rtc_index, data & 15);
|
||||||
|
rtc_index = (rtc_index + 1) & 15;
|
||||||
|
} break;
|
||||||
|
} //switch(rtc_state)
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPC7110::SPC7110() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========
|
||||||
|
//SPC7110MCU
|
||||||
|
//==========
|
||||||
|
|
||||||
|
unsigned SPC7110MCU::size() const {
|
||||||
|
return 0x300000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110MCU::read(unsigned addr) {
|
||||||
|
if(addr <= 0xdfffff) return memory::cartrom.read(spc7110.dx_offset + (addr & 0x0fffff));
|
||||||
|
if(addr <= 0xefffff) return memory::cartrom.read(spc7110.ex_offset + (addr & 0x0fffff));
|
||||||
|
if(addr <= 0xffffff) return memory::cartrom.read(spc7110.fx_offset + (addr & 0x0fffff));
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110MCU::write(unsigned addr, uint8 data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========
|
||||||
|
//SPC7110DCU
|
||||||
|
//==========
|
||||||
|
|
||||||
|
uint8 SPC7110DCU::read(unsigned) {
|
||||||
|
return spc7110.mmio_read(0x4800);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110DCU::write(unsigned, uint8) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========
|
||||||
|
//SPC7110RAM
|
||||||
|
//==========
|
||||||
|
|
||||||
|
unsigned SPC7110RAM::size() const {
|
||||||
|
return 0x2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SPC7110RAM::read(unsigned addr) {
|
||||||
|
return memory::cartram.read(addr & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPC7110RAM::write(unsigned addr, uint8 data) {
|
||||||
|
if(spc7110.r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*****
|
||||||
|
* SPC7110 emulator - version 0.04 (2010-02-14)
|
||||||
|
* Copyright (c) 2008-2010, byuu and neviksti
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* The software is provided "as is" and the author disclaims all warranties
|
||||||
|
* with regard to this software including all implied warranties of
|
||||||
|
* merchantibility and fitness, in no event shall the author be liable for
|
||||||
|
* any special, direct, indirect, or consequential damages or any damages
|
||||||
|
* whatsoever resulting from loss of use, data or profits, whether in an
|
||||||
|
* action of contract, negligence or other tortious action, arising out of
|
||||||
|
* or in connection with the use or performance of this software.
|
||||||
|
*****/
|
||||||
|
|
||||||
|
#include "decomp.hpp"
|
||||||
|
|
||||||
|
class SPC7110 : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
unsigned datarom_addr(unsigned addr);
|
||||||
|
|
||||||
|
unsigned data_pointer();
|
||||||
|
unsigned data_adjust();
|
||||||
|
unsigned data_increment();
|
||||||
|
void set_data_pointer(unsigned addr);
|
||||||
|
void set_data_adjust(unsigned addr);
|
||||||
|
|
||||||
|
void update_time(int offset = 0);
|
||||||
|
time_t create_time();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
//spc7110decomp
|
||||||
|
void decomp_init();
|
||||||
|
uint8 decomp_read();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
SPC7110();
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==================
|
||||||
|
//decompression unit
|
||||||
|
//==================
|
||||||
|
uint8 r4801; //compression table low
|
||||||
|
uint8 r4802; //compression table high
|
||||||
|
uint8 r4803; //compression table bank
|
||||||
|
uint8 r4804; //compression table index
|
||||||
|
uint8 r4805; //decompression buffer index low
|
||||||
|
uint8 r4806; //decompression buffer index high
|
||||||
|
uint8 r4807; //???
|
||||||
|
uint8 r4808; //???
|
||||||
|
uint8 r4809; //compression length low
|
||||||
|
uint8 r480a; //compression length high
|
||||||
|
uint8 r480b; //decompression control register
|
||||||
|
uint8 r480c; //decompression status
|
||||||
|
|
||||||
|
SPC7110Decomp decomp;
|
||||||
|
|
||||||
|
//==============
|
||||||
|
//data port unit
|
||||||
|
//==============
|
||||||
|
uint8 r4811; //data pointer low
|
||||||
|
uint8 r4812; //data pointer high
|
||||||
|
uint8 r4813; //data pointer bank
|
||||||
|
uint8 r4814; //data adjust low
|
||||||
|
uint8 r4815; //data adjust high
|
||||||
|
uint8 r4816; //data increment low
|
||||||
|
uint8 r4817; //data increment high
|
||||||
|
uint8 r4818; //data port control register
|
||||||
|
|
||||||
|
uint8 r481x;
|
||||||
|
|
||||||
|
bool r4814_latch;
|
||||||
|
bool r4815_latch;
|
||||||
|
|
||||||
|
//=========
|
||||||
|
//math unit
|
||||||
|
//=========
|
||||||
|
uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0
|
||||||
|
uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1
|
||||||
|
uint8 r4822; //32-bit dividend B2
|
||||||
|
uint8 r4823; //32-bit dividend B3
|
||||||
|
uint8 r4824; //16-bit multiplier B0
|
||||||
|
uint8 r4825; //16-bit multiplier B1
|
||||||
|
uint8 r4826; //16-bit divisor B0
|
||||||
|
uint8 r4827; //16-bit divisor B1
|
||||||
|
uint8 r4828; //32-bit product B0, 32-bit quotient B0
|
||||||
|
uint8 r4829; //32-bit product B1, 32-bit quotient B1
|
||||||
|
uint8 r482a; //32-bit product B2, 32-bit quotient B2
|
||||||
|
uint8 r482b; //32-bit product B3, 32-bit quotient B3
|
||||||
|
uint8 r482c; //16-bit remainder B0
|
||||||
|
uint8 r482d; //16-bit remainder B1
|
||||||
|
uint8 r482e; //math control register
|
||||||
|
uint8 r482f; //math status
|
||||||
|
|
||||||
|
//===================
|
||||||
|
//memory mapping unit
|
||||||
|
//===================
|
||||||
|
uint8 r4830; //SRAM write enable
|
||||||
|
uint8 r4831; //$[d0-df]:[0000-ffff] mapping
|
||||||
|
uint8 r4832; //$[e0-ef]:[0000-ffff] mapping
|
||||||
|
uint8 r4833; //$[f0-ff]:[0000-ffff] mapping
|
||||||
|
uint8 r4834; //???
|
||||||
|
|
||||||
|
unsigned dx_offset;
|
||||||
|
unsigned ex_offset;
|
||||||
|
unsigned fx_offset;
|
||||||
|
|
||||||
|
//====================
|
||||||
|
//real-time clock unit
|
||||||
|
//====================
|
||||||
|
uint8 r4840; //RTC latch
|
||||||
|
uint8 r4841; //RTC index/data port
|
||||||
|
uint8 r4842; //RTC status
|
||||||
|
|
||||||
|
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write };
|
||||||
|
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c };
|
||||||
|
unsigned rtc_state;
|
||||||
|
unsigned rtc_mode;
|
||||||
|
unsigned rtc_index;
|
||||||
|
|
||||||
|
static const unsigned months[12];
|
||||||
|
friend class SPC7110MCU;
|
||||||
|
friend class SPC7110DCU;
|
||||||
|
friend class SPC7110RAM;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPC7110MCU : public Memory {
|
||||||
|
public:
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPC7110DCU : public Memory {
|
||||||
|
public:
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPC7110RAM : public Memory {
|
||||||
|
public:
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SPC7110 spc7110;
|
||||||
|
extern SPC7110MCU spc7110mcu;
|
||||||
|
extern SPC7110DCU spc7110dcu;
|
||||||
|
extern SPC7110RAM spc7110ram;
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifdef SRTC_CPP
|
||||||
|
|
||||||
|
void SRTC::serialize(serializer &s) {
|
||||||
|
s.integer(rtc_mode);
|
||||||
|
s.integer(rtc_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,231 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SRTC_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
SRTC srtc;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
void SRTC::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::reset() {
|
||||||
|
rtc_mode = RtcRead;
|
||||||
|
rtc_index = -1;
|
||||||
|
update_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::update_time() {
|
||||||
|
time_t rtc_time
|
||||||
|
= (memory::cartrtc.read(16) << 0)
|
||||||
|
| (memory::cartrtc.read(17) << 8)
|
||||||
|
| (memory::cartrtc.read(18) << 16)
|
||||||
|
| (memory::cartrtc.read(19) << 24);
|
||||||
|
time_t current_time = time(0);
|
||||||
|
|
||||||
|
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||||
|
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||||
|
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||||
|
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||||
|
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||||
|
//or whether time_t is signed or unsigned.
|
||||||
|
time_t diff
|
||||||
|
= (current_time >= rtc_time)
|
||||||
|
? (current_time - rtc_time)
|
||||||
|
: (std::numeric_limits<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
|
||||||
|
if(diff > std::numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||||
|
|
||||||
|
if(diff > 0) {
|
||||||
|
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||||
|
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||||
|
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8);
|
||||||
|
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||||
|
unsigned weekday = memory::cartrtc.read(12);
|
||||||
|
|
||||||
|
day--;
|
||||||
|
month--;
|
||||||
|
year += 1000;
|
||||||
|
|
||||||
|
second += diff;
|
||||||
|
while(second >= 60) {
|
||||||
|
second -= 60;
|
||||||
|
|
||||||
|
minute++;
|
||||||
|
if(minute < 60) continue;
|
||||||
|
minute = 0;
|
||||||
|
|
||||||
|
hour++;
|
||||||
|
if(hour < 24) continue;
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
day++;
|
||||||
|
weekday = (weekday + 1) % 7;
|
||||||
|
unsigned days = months[month % 12];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((year % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
if(day < days) continue;
|
||||||
|
day = 0;
|
||||||
|
|
||||||
|
month++;
|
||||||
|
if(month < 12) continue;
|
||||||
|
month = 0;
|
||||||
|
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
day++;
|
||||||
|
month++;
|
||||||
|
year -= 1000;
|
||||||
|
|
||||||
|
memory::cartrtc.write( 0, second % 10);
|
||||||
|
memory::cartrtc.write( 1, second / 10);
|
||||||
|
memory::cartrtc.write( 2, minute % 10);
|
||||||
|
memory::cartrtc.write( 3, minute / 10);
|
||||||
|
memory::cartrtc.write( 4, hour % 10);
|
||||||
|
memory::cartrtc.write( 5, hour / 10);
|
||||||
|
memory::cartrtc.write( 6, day % 10);
|
||||||
|
memory::cartrtc.write( 7, day / 10);
|
||||||
|
memory::cartrtc.write( 8, month);
|
||||||
|
memory::cartrtc.write( 9, year % 10);
|
||||||
|
memory::cartrtc.write(10, (year / 10) % 10);
|
||||||
|
memory::cartrtc.write(11, year / 100);
|
||||||
|
memory::cartrtc.write(12, weekday % 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::cartrtc.write(16, current_time >> 0);
|
||||||
|
memory::cartrtc.write(17, current_time >> 8);
|
||||||
|
memory::cartrtc.write(18, current_time >> 16);
|
||||||
|
memory::cartrtc.write(19, current_time >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns day of week for specified date
|
||||||
|
//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday
|
||||||
|
//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008
|
||||||
|
unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
|
||||||
|
unsigned y = 1900, m = 1; //epoch is 1900-01-01
|
||||||
|
unsigned sum = 0; //number of days passed since epoch
|
||||||
|
|
||||||
|
year = max(1900, year);
|
||||||
|
month = max(1, min(12, month));
|
||||||
|
day = max(1, min(31, day));
|
||||||
|
|
||||||
|
while(y < year) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((y % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
sum += leapyear ? 366 : 365;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(m < month) {
|
||||||
|
unsigned days = months[m - 1];
|
||||||
|
if(days == 28) {
|
||||||
|
bool leapyear = false;
|
||||||
|
if((y % 4) == 0) {
|
||||||
|
leapyear = true;
|
||||||
|
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||||
|
}
|
||||||
|
if(leapyear) days++;
|
||||||
|
}
|
||||||
|
sum += days;
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += day - 1;
|
||||||
|
return (sum + 1) % 7; //1900-01-01 was a Monday
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SRTC::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2800) {
|
||||||
|
if(rtc_mode != RtcRead) return 0x00;
|
||||||
|
|
||||||
|
if(rtc_index < 0) {
|
||||||
|
update_time();
|
||||||
|
rtc_index++;
|
||||||
|
return 0x0f;
|
||||||
|
} else if(rtc_index > 12) {
|
||||||
|
rtc_index = -1;
|
||||||
|
return 0x0f;
|
||||||
|
} else {
|
||||||
|
return memory::cartrtc.read(rtc_index++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SRTC::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x2801) {
|
||||||
|
data &= 0x0f; //only the low four bits are used
|
||||||
|
|
||||||
|
if(data == 0x0d) {
|
||||||
|
rtc_mode = RtcRead;
|
||||||
|
rtc_index = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data == 0x0e) {
|
||||||
|
rtc_mode = RtcCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data == 0x0f) return; //unknown behavior
|
||||||
|
|
||||||
|
if(rtc_mode == RtcWrite) {
|
||||||
|
if(rtc_index >= 0 && rtc_index < 12) {
|
||||||
|
memory::cartrtc.write(rtc_index++, data);
|
||||||
|
|
||||||
|
if(rtc_index == 12) {
|
||||||
|
//day of week is automatically calculated and written
|
||||||
|
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||||
|
unsigned month = memory::cartrtc.read( 8);
|
||||||
|
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||||
|
year += 1000;
|
||||||
|
|
||||||
|
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(rtc_mode == RtcCommand) {
|
||||||
|
if(data == 0) {
|
||||||
|
rtc_mode = RtcWrite;
|
||||||
|
rtc_index = 0;
|
||||||
|
} else if(data == 4) {
|
||||||
|
rtc_mode = RtcReady;
|
||||||
|
rtc_index = -1;
|
||||||
|
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
|
||||||
|
} else {
|
||||||
|
//unknown behavior
|
||||||
|
rtc_mode = RtcReady;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SRTC::SRTC() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
class SRTC : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
SRTC();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const unsigned months[12];
|
||||||
|
enum RtcMode { RtcReady, RtcCommand, RtcRead, RtcWrite };
|
||||||
|
unsigned rtc_mode;
|
||||||
|
signed rtc_index;
|
||||||
|
|
||||||
|
void update_time();
|
||||||
|
unsigned weekday(unsigned year, unsigned month, unsigned day);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SRTC srtc;
|
|
@ -0,0 +1,130 @@
|
||||||
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
|
const int16 ST0010::sin_table[256] = {
|
||||||
|
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
||||||
|
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
||||||
|
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
||||||
|
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
|
||||||
|
0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
|
||||||
|
0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
|
||||||
|
0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
|
||||||
|
0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
|
||||||
|
0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
|
||||||
|
0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
|
||||||
|
0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
|
||||||
|
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
|
||||||
|
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
|
||||||
|
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
|
||||||
|
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
|
||||||
|
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
|
||||||
|
0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
|
||||||
|
-0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
|
||||||
|
-0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
|
||||||
|
-0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
|
||||||
|
-0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
|
||||||
|
-0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
|
||||||
|
-0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
|
||||||
|
-0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
|
||||||
|
-0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
|
||||||
|
-0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
|
||||||
|
-0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
|
||||||
|
-0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
|
||||||
|
-0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
|
||||||
|
-0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
|
||||||
|
-0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
|
||||||
|
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16 ST0010::mode7_scale[176] = {
|
||||||
|
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
||||||
|
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
||||||
|
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
||||||
|
0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
|
||||||
|
0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
|
||||||
|
0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
|
||||||
|
0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
|
||||||
|
0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
|
||||||
|
0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
|
||||||
|
0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
|
||||||
|
0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
|
||||||
|
0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
|
||||||
|
0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
|
||||||
|
0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
|
||||||
|
0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
|
||||||
|
0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
|
||||||
|
0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
|
||||||
|
0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
|
||||||
|
0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
|
||||||
|
0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
|
||||||
|
0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
|
||||||
|
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8 ST0010::arctan[32][32] = {
|
||||||
|
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
||||||
|
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
||||||
|
0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
|
||||||
|
{ 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
|
||||||
|
0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
|
||||||
|
{ 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
|
||||||
|
0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
|
||||||
|
{ 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
|
||||||
|
0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
|
||||||
|
{ 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||||||
|
0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
|
||||||
|
{ 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
|
||||||
|
0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
|
||||||
|
{ 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
|
||||||
|
0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
|
||||||
|
{ 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
|
||||||
|
0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
|
||||||
|
{ 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
|
||||||
|
0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
|
||||||
|
{ 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
|
||||||
|
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
|
||||||
|
{ 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
|
||||||
|
0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
|
||||||
|
{ 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
|
||||||
|
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
|
||||||
|
{ 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
|
||||||
|
0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
|
||||||
|
{ 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
|
||||||
|
0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
|
||||||
|
{ 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
|
||||||
|
0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
|
||||||
|
{ 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
|
||||||
|
0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
|
||||||
|
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
|
||||||
|
0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
|
||||||
|
{ 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
|
||||||
|
0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
|
||||||
|
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
|
||||||
|
0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
|
||||||
|
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
|
||||||
|
0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
|
||||||
|
{ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
|
||||||
|
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
|
||||||
|
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
|
||||||
|
0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
|
||||||
|
0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
|
||||||
|
{ 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
|
||||||
|
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
|
||||||
|
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
|
||||||
|
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
|
||||||
|
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
|
||||||
|
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
||||||
|
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,261 @@
|
||||||
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
|
//ST-0010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
||||||
|
//bsnes port - Copyright (C) 2007 byuu
|
||||||
|
|
||||||
|
void ST0010::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 ST0010::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 ST0010::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 ST0010::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 ST0010::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 ST0010::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 off 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 ST0010::op_06() {
|
||||||
|
int16 multiplicand = readw(0x0000);
|
||||||
|
int16 multiplier = readw(0x0002);
|
||||||
|
int32 product;
|
||||||
|
|
||||||
|
product = multiplicand * multiplier << 1;
|
||||||
|
|
||||||
|
writed(0x0010, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::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 ST0010::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
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
|
void ST0010::serialize(serializer &s) {
|
||||||
|
s.array(ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define ST0010_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
ST0010 st0010;
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "opcodes.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
void ST0010::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 ST0010::sin(int16 theta) {
|
||||||
|
return sin_table[(theta >> 8) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 ST0010::cos(int16 theta) {
|
||||||
|
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 ST0010::readb(uint16 addr) {
|
||||||
|
return ram[addr & 0xfff];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 ST0010::readw(uint16 addr) {
|
||||||
|
return (readb(addr + 0) << 0) |
|
||||||
|
(readb(addr + 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ST0010::readd(uint16 addr) {
|
||||||
|
return (readb(addr + 0) << 0) |
|
||||||
|
(readb(addr + 1) << 8) |
|
||||||
|
(readb(addr + 2) << 16) |
|
||||||
|
(readb(addr + 3) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::writeb(uint16 addr, uint8 data) {
|
||||||
|
ram[addr & 0xfff] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::writew(uint16 addr, uint16 data) {
|
||||||
|
writeb(addr + 0, data >> 0);
|
||||||
|
writeb(addr + 1, data >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::writed(uint16 addr, uint32 data) {
|
||||||
|
writeb(addr + 0, data >> 0);
|
||||||
|
writeb(addr + 1, data >> 8);
|
||||||
|
writeb(addr + 2, data >> 16);
|
||||||
|
writeb(addr + 3, data >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void ST0010::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::reset() {
|
||||||
|
memset(ram, 0x00, sizeof ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
uint8 ST0010::read(unsigned addr) {
|
||||||
|
return readb(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0010::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
class ST0010 : public Memory {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 read(unsigned addr);
|
||||||
|
void write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x1000];
|
||||||
|
static const int16 sin_table[256];
|
||||||
|
static const int16 mode7_scale[176];
|
||||||
|
static const uint8 arctan[32][32];
|
||||||
|
|
||||||
|
//interfaces to sin table
|
||||||
|
int16 sin(int16 theta);
|
||||||
|
int16 cos(int16 theta);
|
||||||
|
|
||||||
|
//interfaces to ram buffer
|
||||||
|
uint8 readb (uint16 addr);
|
||||||
|
uint16 readw (uint16 addr);
|
||||||
|
uint32 readd (uint16 addr);
|
||||||
|
void writeb(uint16 addr, uint8 data);
|
||||||
|
void writew(uint16 addr, uint16 data);
|
||||||
|
void writed(uint16 addr, uint32 data);
|
||||||
|
|
||||||
|
//opcodes
|
||||||
|
void op_01();
|
||||||
|
void op_02();
|
||||||
|
void op_03();
|
||||||
|
void op_04();
|
||||||
|
void op_05();
|
||||||
|
void op_06();
|
||||||
|
void op_07();
|
||||||
|
void op_08();
|
||||||
|
|
||||||
|
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ST0010 st0010;
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define ST0011_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
ST0011 st0011;
|
||||||
|
|
||||||
|
void ST0011::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0011::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0011::power() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0011::reset() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
class ST0011 {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ST0011 st0011;
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define ST0018_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
ST0018 st0018;
|
||||||
|
|
||||||
|
uint8 ST0018::mmio_read(unsigned addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
if(addr == 0x3800) return regs.r3800;
|
||||||
|
if(addr == 0x3804) return regs.r3804;
|
||||||
|
return cpu.regs.mdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::mmio_write(unsigned addr, uint8 data) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
if(addr == 0x3802) {
|
||||||
|
switch(regs.mode) {
|
||||||
|
case Waiting: {
|
||||||
|
switch(data) {
|
||||||
|
case 0x01: regs.r3800 = regs.r3800_01; break;
|
||||||
|
case 0xaa: op_board_upload(); break;
|
||||||
|
case 0xb2: op_b2(); break;
|
||||||
|
case 0xb3: op_b3(); break;
|
||||||
|
case 0xb4: op_b4(); break;
|
||||||
|
case 0xb5: op_b5(); break;
|
||||||
|
case 0xf1: op_query_chip(); break;
|
||||||
|
case 0xf2: op_query_chip(); break;
|
||||||
|
default: fprintf(stdout, "* ST018 w3802::%.2x\n", data); break;
|
||||||
|
}
|
||||||
|
} return;
|
||||||
|
|
||||||
|
case BoardUpload: {
|
||||||
|
op_board_upload(data);
|
||||||
|
} return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0x3804) {
|
||||||
|
regs.w3804 <<= 8;
|
||||||
|
regs.w3804 |= data;
|
||||||
|
regs.w3804 &= 0xffffff;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::reset() {
|
||||||
|
regs.mode = Waiting;
|
||||||
|
regs.r3800 = 0x00;
|
||||||
|
regs.r3804 = 0x85;
|
||||||
|
regs.w3804 = 0;
|
||||||
|
for(unsigned i = 0; i < 97; i++) board[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===============
|
||||||
|
//ST-0018 opcodes
|
||||||
|
//===============
|
||||||
|
|
||||||
|
void ST0018::op_board_upload() {
|
||||||
|
regs.mode = BoardUpload;
|
||||||
|
regs.counter = 0;
|
||||||
|
regs.r3800 = 0xe0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_board_upload(uint8 data) {
|
||||||
|
board[regs.counter] = data;
|
||||||
|
regs.r3800 = 96 - regs.counter;
|
||||||
|
regs.counter++;
|
||||||
|
if(regs.counter >= 97) {
|
||||||
|
regs.mode = Waiting;
|
||||||
|
#if 0
|
||||||
|
for(unsigned y = 0; y < 9; y++) {
|
||||||
|
for(unsigned x = 0; x < 9; x++) {
|
||||||
|
fprintf(stdout, "%.2x ", board[y * 9 + x]);
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
}
|
||||||
|
for(unsigned n = 0; n < 16; n++) fprintf(stdout, "%.2x ", board[81 + n]);
|
||||||
|
fprintf(stdout, "\n\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_b2() {
|
||||||
|
fprintf(stdout, "* ST018 w3802::b2\n");
|
||||||
|
regs.r3800 = 0xe0;
|
||||||
|
regs.r3800_01 = 0; //unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_b3() {
|
||||||
|
fprintf(stdout, "* ST018 w3802::b3\n");
|
||||||
|
regs.r3800 = 0xe0;
|
||||||
|
regs.r3800_01 = 1; //0 = player lost?
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_b4() {
|
||||||
|
fprintf(stdout, "* ST018 w3802::b4\n");
|
||||||
|
regs.r3800 = 0xe0;
|
||||||
|
regs.r3800_01 = 1; //0 = player won?
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_b5() {
|
||||||
|
fprintf(stdout, "* ST018 w3802::b5\n");
|
||||||
|
regs.r3800 = 0xe0;
|
||||||
|
regs.r3800_01 = 0; //1 = move will result in checkmate?
|
||||||
|
}
|
||||||
|
|
||||||
|
void ST0018::op_query_chip() {
|
||||||
|
regs.r3800 = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
class ST0018 : public MMIO {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
|
enum mode_t { Waiting, BoardUpload };
|
||||||
|
struct regs_t {
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
uint8 r3800;
|
||||||
|
uint8 r3800_01;
|
||||||
|
uint8 r3804;
|
||||||
|
|
||||||
|
unsigned w3804;
|
||||||
|
unsigned counter;
|
||||||
|
} regs;
|
||||||
|
|
||||||
|
enum PieceID {
|
||||||
|
Pawn = 0x00, //foot soldier
|
||||||
|
Lance = 0x04, //incense chariot
|
||||||
|
Knight = 0x08, //cassia horse
|
||||||
|
Silver = 0x0c, //silver general
|
||||||
|
Gold = 0x10, //gold general
|
||||||
|
Rook = 0x14, //flying chariot
|
||||||
|
Bishop = 0x18, //angle mover
|
||||||
|
King = 0x1c, //king
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PieceFlag {
|
||||||
|
PlayerA = 0x20,
|
||||||
|
PlayerB = 0x40,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 board[9 * 9 + 16];
|
||||||
|
|
||||||
|
private:
|
||||||
|
void op_board_upload();
|
||||||
|
void op_board_upload(uint8 data);
|
||||||
|
void op_b2();
|
||||||
|
void op_b3();
|
||||||
|
void op_b4();
|
||||||
|
void op_b5();
|
||||||
|
void op_query_chip();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ST0018 st0018;
|
|
@ -0,0 +1,97 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
SuperFXBus superfxbus;
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
SuperFXGSUROM gsurom;
|
||||||
|
SuperFXGSURAM gsuram;
|
||||||
|
SuperFXCPUROM fxrom;
|
||||||
|
SuperFXCPURAM fxram;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFXBus::init() {
|
||||||
|
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||||
|
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
|
||||||
|
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
|
||||||
|
map(MapMode::Linear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
|
||||||
|
map(MapMode::Linear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ROM / RAM access from the SuperFX CPU
|
||||||
|
|
||||||
|
unsigned SuperFXGSUROM::size() const {
|
||||||
|
return memory::cartrom.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SuperFXGSUROM::read(unsigned addr) {
|
||||||
|
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
|
superfx.add_clocks(6);
|
||||||
|
superfx.synchronize_cpu();
|
||||||
|
}
|
||||||
|
return memory::cartrom.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
|
||||||
|
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
|
superfx.add_clocks(6);
|
||||||
|
superfx.synchronize_cpu();
|
||||||
|
}
|
||||||
|
memory::cartrom.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SuperFXGSURAM::size() const {
|
||||||
|
return memory::cartram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SuperFXGSURAM::read(unsigned addr) {
|
||||||
|
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
|
superfx.add_clocks(6);
|
||||||
|
superfx.synchronize_cpu();
|
||||||
|
}
|
||||||
|
return memory::cartram.read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
|
||||||
|
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
|
superfx.add_clocks(6);
|
||||||
|
superfx.synchronize_cpu();
|
||||||
|
}
|
||||||
|
memory::cartram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ROM / RAM access from the S-CPU
|
||||||
|
|
||||||
|
unsigned SuperFXCPUROM::size() const {
|
||||||
|
return memory::cartrom.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 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 data) {
|
||||||
|
memory::cartrom.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned SuperFXCPURAM::size() const {
|
||||||
|
return memory::cartram.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 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 data) {
|
||||||
|
memory::cartram.write(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
struct SuperFXBus : Bus {
|
||||||
|
void init();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SuperFXGSUROM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned);
|
||||||
|
void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SuperFXGSURAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned);
|
||||||
|
void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SuperFXCPUROM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned);
|
||||||
|
void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SuperFXCPURAM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
|
uint8 read(unsigned);
|
||||||
|
void write(unsigned, uint8);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
extern SuperFXGSUROM gsurom;
|
||||||
|
extern SuperFXGSURAM gsuram;
|
||||||
|
extern SuperFXCPUROM fxrom;
|
||||||
|
extern SuperFXCPURAM fxram;
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
#include "opcodes.cpp"
|
||||||
|
#include "opcode_table.cpp"
|
||||||
|
|
||||||
|
uint8 SuperFX::color(uint8 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 x, uint8 y) {
|
||||||
|
uint8 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 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 SuperFX::rpix(uint8 x, uint8 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 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 x = cache.offset << 3;
|
||||||
|
uint8 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 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
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "registers.hpp"
|
||||||
|
|
||||||
|
uint8 color(uint8 source);
|
||||||
|
void plot(uint8 x, uint8 y);
|
||||||
|
uint8 rpix(uint8 x, uint8 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();
|
|
@ -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
|
|
@ -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)pipe();
|
||||||
|
}
|
||||||
|
|
||||||
|
//$06 blt e
|
||||||
|
void SuperFX::op_blt() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if((regs.sfr.s ^ regs.sfr.ov) == 0) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$07 bge e
|
||||||
|
void SuperFX::op_bge() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if((regs.sfr.s ^ regs.sfr.ov) == 1) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$08 bne e
|
||||||
|
void SuperFX::op_bne() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.z == 0) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$09 beq e
|
||||||
|
void SuperFX::op_beq() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.z == 1) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0a bpl e
|
||||||
|
void SuperFX::op_bpl() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.s == 0) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0b bmi e
|
||||||
|
void SuperFX::op_bmi() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.s == 1) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0c bcc e
|
||||||
|
void SuperFX::op_bcc() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.cy == 0) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0d bcs e
|
||||||
|
void SuperFX::op_bcs() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.cy == 1) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0e bvc e
|
||||||
|
void SuperFX::op_bvc() {
|
||||||
|
int e = (int8)pipe();
|
||||||
|
if(regs.sfr.ov == 0) regs.r[15] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//$0f bvs e
|
||||||
|
void SuperFX::op_bvs() {
|
||||||
|
int e = (int8)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 = n;
|
||||||
|
} else {
|
||||||
|
regs.r[n] = regs.sr();
|
||||||
|
regs.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//$20-2f: with rN
|
||||||
|
template<int n> void SuperFX::op_with_r() {
|
||||||
|
regs.sreg = n;
|
||||||
|
regs.dreg = 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)regs.sr() * (int8)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)regs.sr() * (uint8)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)regs.sr() * (int8)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)regs.sr() * (uint8)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)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] & 0x7f;
|
||||||
|
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)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 = 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() & 0x7f;
|
||||||
|
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)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
|
|
@ -0,0 +1,176 @@
|
||||||
|
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
|
||||||
|
struct reg16_t {
|
||||||
|
uint16 data;
|
||||||
|
function<void (uint16)> on_modify;
|
||||||
|
|
||||||
|
inline operator unsigned() const { return data; }
|
||||||
|
inline uint16 assign(uint16 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) {}
|
||||||
|
reg16_t(const reg16_t&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 unsigned() 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 unsigned() const {
|
||||||
|
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
|
||||||
|
}
|
||||||
|
|
||||||
|
scmr_t& operator=(uint8 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 unsigned() const {
|
||||||
|
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
por_t& operator=(uint8 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 unsigned() const {
|
||||||
|
return (irq << 7) | (ms0 << 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgr_t& operator=(uint8 data) {
|
||||||
|
irq = data & 0x80;
|
||||||
|
ms0 = data & 0x20;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct regs_t {
|
||||||
|
uint8 pipeline;
|
||||||
|
uint16 ramaddr;
|
||||||
|
|
||||||
|
reg16_t r[16]; //general purpose registers
|
||||||
|
sfr_t sfr; //status flag register
|
||||||
|
uint8 pbr; //program bank register
|
||||||
|
uint8 rombr; //game pack ROM bank register
|
||||||
|
bool rambr; //game pack RAM bank register
|
||||||
|
uint16 cbr; //cache base register
|
||||||
|
uint8 scbr; //screen base register
|
||||||
|
scmr_t scmr; //screen mode register
|
||||||
|
uint8 colr; //color register
|
||||||
|
por_t por; //plot option register
|
||||||
|
bool bramr; //back-up RAM register
|
||||||
|
uint8 vcr; //version code register
|
||||||
|
cfgr_t cfgr; //config register
|
||||||
|
bool clsr; //clock select register
|
||||||
|
|
||||||
|
unsigned romcl; //clock ticks until romdr is valid
|
||||||
|
uint8 romdr; //ROM buffer data register
|
||||||
|
|
||||||
|
unsigned ramcl; //clock ticks until ramdr is valid
|
||||||
|
uint16 ramar; //RAM buffer address register
|
||||||
|
uint8 ramdr; //RAM buffer data register
|
||||||
|
|
||||||
|
unsigned sreg, dreg;
|
||||||
|
reg16_t& sr() { return r[sreg]; } //source register (from)
|
||||||
|
reg16_t& dr() { return r[dreg]; } //destination register (to)
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
sfr.b = 0;
|
||||||
|
sfr.alt1 = 0;
|
||||||
|
sfr.alt2 = 0;
|
||||||
|
|
||||||
|
sreg = 0;
|
||||||
|
dreg = 0;
|
||||||
|
}
|
||||||
|
} regs;
|
||||||
|
|
||||||
|
struct cache_t {
|
||||||
|
uint8 buffer[512];
|
||||||
|
bool valid[32];
|
||||||
|
} cache;
|
||||||
|
|
||||||
|
struct pixelcache_t {
|
||||||
|
uint16 offset;
|
||||||
|
uint8 bitpend;
|
||||||
|
uint8 data[8];
|
||||||
|
} pixelcache[2];
|
|
@ -0,0 +1,279 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#endif
|
|
@ -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);
|
|
@ -0,0 +1,71 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
uint8 SuperFX::op_read(uint16 addr) {
|
||||||
|
uint16 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 SuperFX::peekpipe() {
|
||||||
|
uint8 result = regs.pipeline;
|
||||||
|
regs.pipeline = op_read(regs.r[15]);
|
||||||
|
r15_modified = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SuperFX::pipe() {
|
||||||
|
uint8 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 SuperFX::cache_mmio_read(uint16 addr) {
|
||||||
|
addr = (addr + regs.cbr) & 511;
|
||||||
|
return cache.buffer[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::cache_mmio_write(uint16 addr, uint8 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,9 @@
|
||||||
|
uint8 op_read(uint16 addr);
|
||||||
|
alwaysinline uint8 peekpipe();
|
||||||
|
alwaysinline uint8 pipe();
|
||||||
|
|
||||||
|
void cache_flush();
|
||||||
|
uint8 cache_mmio_read(uint16 addr);
|
||||||
|
void cache_mmio_write(uint16 addr, uint8 data);
|
||||||
|
|
||||||
|
void memory_reset();
|
|
@ -0,0 +1,118 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
uint8 SuperFX::mmio_read(unsigned addr) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
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 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 data) {
|
||||||
|
cpu.synchronize_coprocessor();
|
||||||
|
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 & 0x7f;
|
||||||
|
cache_flush();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x3037: {
|
||||||
|
regs.cfgr = data;
|
||||||
|
update_speed();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x3038: {
|
||||||
|
regs.scbr = data;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x3039: {
|
||||||
|
regs.clsr = data;
|
||||||
|
update_speed();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 0x303a: {
|
||||||
|
regs.scmr = data;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
uint8 mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8 data);
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
void SuperFX::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
|
||||||
|
//superfx.hpp
|
||||||
|
s.integer(clockmode);
|
||||||
|
s.integer(instruction_counter);
|
||||||
|
|
||||||
|
//core/registers.hpp
|
||||||
|
s.integer(regs.pipeline);
|
||||||
|
s.integer(regs.ramaddr);
|
||||||
|
|
||||||
|
s.integer(regs.r[ 0].data);
|
||||||
|
s.integer(regs.r[ 1].data);
|
||||||
|
s.integer(regs.r[ 2].data);
|
||||||
|
s.integer(regs.r[ 3].data);
|
||||||
|
s.integer(regs.r[ 4].data);
|
||||||
|
s.integer(regs.r[ 5].data);
|
||||||
|
s.integer(regs.r[ 6].data);
|
||||||
|
s.integer(regs.r[ 7].data);
|
||||||
|
s.integer(regs.r[ 8].data);
|
||||||
|
s.integer(regs.r[ 9].data);
|
||||||
|
s.integer(regs.r[10].data);
|
||||||
|
s.integer(regs.r[11].data);
|
||||||
|
s.integer(regs.r[12].data);
|
||||||
|
s.integer(regs.r[13].data);
|
||||||
|
s.integer(regs.r[14].data);
|
||||||
|
s.integer(regs.r[15].data);
|
||||||
|
|
||||||
|
s.integer(regs.sfr.irq);
|
||||||
|
s.integer(regs.sfr.b);
|
||||||
|
s.integer(regs.sfr.ih);
|
||||||
|
s.integer(regs.sfr.il);
|
||||||
|
s.integer(regs.sfr.alt2);
|
||||||
|
s.integer(regs.sfr.alt1);
|
||||||
|
s.integer(regs.sfr.r);
|
||||||
|
s.integer(regs.sfr.g);
|
||||||
|
s.integer(regs.sfr.ov);
|
||||||
|
s.integer(regs.sfr.s);
|
||||||
|
s.integer(regs.sfr.cy);
|
||||||
|
s.integer(regs.sfr.z);
|
||||||
|
|
||||||
|
s.integer(regs.pbr);
|
||||||
|
s.integer(regs.rombr);
|
||||||
|
s.integer(regs.rambr);
|
||||||
|
s.integer(regs.cbr);
|
||||||
|
s.integer(regs.scbr);
|
||||||
|
|
||||||
|
s.integer(regs.scmr.ht);
|
||||||
|
s.integer(regs.scmr.ron);
|
||||||
|
s.integer(regs.scmr.ran);
|
||||||
|
s.integer(regs.scmr.md);
|
||||||
|
|
||||||
|
s.integer(regs.colr);
|
||||||
|
|
||||||
|
s.integer(regs.por.obj);
|
||||||
|
s.integer(regs.por.freezehigh);
|
||||||
|
s.integer(regs.por.highnibble);
|
||||||
|
s.integer(regs.por.dither);
|
||||||
|
s.integer(regs.por.transparent);
|
||||||
|
|
||||||
|
s.integer(regs.bramr);
|
||||||
|
s.integer(regs.vcr);
|
||||||
|
|
||||||
|
s.integer(regs.cfgr.irq);
|
||||||
|
s.integer(regs.cfgr.ms0);
|
||||||
|
|
||||||
|
s.integer(regs.clsr);
|
||||||
|
|
||||||
|
s.integer(regs.romcl);
|
||||||
|
s.integer(regs.romdr);
|
||||||
|
|
||||||
|
s.integer(regs.ramcl);
|
||||||
|
s.integer(regs.ramar);
|
||||||
|
s.integer(regs.ramdr);
|
||||||
|
|
||||||
|
s.integer(regs.sreg);
|
||||||
|
s.integer(regs.dreg);
|
||||||
|
|
||||||
|
s.array(cache.buffer);
|
||||||
|
s.array(cache.valid);
|
||||||
|
|
||||||
|
for(unsigned i = 0; i < 2; i++) {
|
||||||
|
s.integer(pixelcache[i].offset);
|
||||||
|
s.integer(pixelcache[i].bitpend);
|
||||||
|
s.array(pixelcache[i].data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//timing/timing.hpp
|
||||||
|
s.integer(cache_access_speed);
|
||||||
|
s.integer(memory_access_speed);
|
||||||
|
s.integer(r15_modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define SUPERFX_CPP
|
||||||
|
namespace SNES {
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
|
#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() { superfx.enter(); }
|
||||||
|
|
||||||
|
void SuperFX::enter() {
|
||||||
|
while(true) {
|
||||||
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.sfr.g == 0) {
|
||||||
|
add_clocks(6);
|
||||||
|
synchronize_cpu();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
|
||||||
|
if(r15_modified == false) regs.r[15]++;
|
||||||
|
|
||||||
|
if(++instruction_counter >= 128) {
|
||||||
|
instruction_counter = 0;
|
||||||
|
synchronize_cpu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::init() {
|
||||||
|
initialize_opcode_table();
|
||||||
|
regs.r[14].on_modify = { &SuperFX::r14_modify, this };
|
||||||
|
regs.r[15].on_modify = { &SuperFX::r15_modify, this };
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::enable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::power() {
|
||||||
|
clockmode = config.superfx.speed;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::reset() {
|
||||||
|
create(SuperFX::Enter, system.cpu_frequency());
|
||||||
|
superfxbus.init();
|
||||||
|
instruction_counter = 0;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "bus/bus.hpp"
|
||||||
|
|
||||||
|
class SuperFX : public Coprocessor, public MMIO {
|
||||||
|
public:
|
||||||
|
#include "core/core.hpp"
|
||||||
|
#include "memory/memory.hpp"
|
||||||
|
#include "mmio/mmio.hpp"
|
||||||
|
#include "timing/timing.hpp"
|
||||||
|
#include "disasm/disasm.hpp"
|
||||||
|
|
||||||
|
static void Enter();
|
||||||
|
void enter();
|
||||||
|
void init();
|
||||||
|
void enable();
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned clockmode;
|
||||||
|
unsigned instruction_counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SuperFX superfx;
|
||||||
|
extern SuperFXBus superfxbus;
|
|
@ -0,0 +1,97 @@
|
||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
step(clocks);
|
||||||
|
synchronize_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SuperFX::rombuffer_read() {
|
||||||
|
rombuffer_sync();
|
||||||
|
return regs.romdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::rambuffer_sync() {
|
||||||
|
if(regs.ramcl) add_clocks(regs.ramcl);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 SuperFX::rambuffer_read(uint16 addr) {
|
||||||
|
rambuffer_sync();
|
||||||
|
return superfxbus.read(0x700000 + (regs.rambr << 16) + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::rambuffer_write(uint16 addr, uint8 data) {
|
||||||
|
rambuffer_sync();
|
||||||
|
regs.ramcl = memory_access_speed;
|
||||||
|
regs.ramar = addr;
|
||||||
|
regs.ramdr = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::r14_modify(uint16 data) {
|
||||||
|
regs.r[14].data = data;
|
||||||
|
rombuffer_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::r15_modify(uint16 data) {
|
||||||
|
regs.r[15].data = data;
|
||||||
|
r15_modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::update_speed() {
|
||||||
|
//force SuperFX1 mode?
|
||||||
|
if(clockmode == 1) {
|
||||||
|
cache_access_speed = 2;
|
||||||
|
memory_access_speed = 6;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//force SuperFX2 mode?
|
||||||
|
if(clockmode == 2) {
|
||||||
|
cache_access_speed = 1;
|
||||||
|
memory_access_speed = 5;
|
||||||
|
regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//default: allow S-CPU to select mode
|
||||||
|
cache_access_speed = (regs.clsr ? 1 : 2);
|
||||||
|
memory_access_speed = (regs.clsr ? 5 : 6);
|
||||||
|
if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperFX::timing_reset() {
|
||||||
|
update_speed();
|
||||||
|
r15_modified = false;
|
||||||
|
|
||||||
|
regs.romcl = 0;
|
||||||
|
regs.romdr = 0;
|
||||||
|
|
||||||
|
regs.ramcl = 0;
|
||||||
|
regs.ramar = 0;
|
||||||
|
regs.ramdr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
unsigned cache_access_speed;
|
||||||
|
unsigned memory_access_speed;
|
||||||
|
bool r15_modified;
|
||||||
|
|
||||||
|
void add_clocks(unsigned clocks);
|
||||||
|
|
||||||
|
void rombuffer_sync();
|
||||||
|
void rombuffer_update();
|
||||||
|
uint8 rombuffer_read();
|
||||||
|
|
||||||
|
void rambuffer_sync();
|
||||||
|
uint8 rambuffer_read(uint16 addr);
|
||||||
|
void rambuffer_write(uint16 addr, uint8 data);
|
||||||
|
|
||||||
|
void r14_modify(uint16);
|
||||||
|
void r15_modify(uint16);
|
||||||
|
|
||||||
|
void update_speed();
|
||||||
|
void timing_reset();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue