mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-21 01:01:41 +02:00
Compare commits
68 Commits
v056
...
graft-poin
Author | SHA1 | Date | |
---|---|---|---|
|
81f43a4d01 | ||
|
9ea739aec1 | ||
|
254a5016e1 | ||
|
dcc661cb28 | ||
|
431d5c8db7 | ||
|
7b7a95af67 | ||
|
a266a2b5e2 | ||
|
53f03be5a2 | ||
|
77375c3c68 | ||
|
dce3e61f06 | ||
|
20b44ddfd1 | ||
|
79f20030a0 | ||
|
79b939e1c7 | ||
|
3ae74ff5a5 | ||
|
7351b910c5 | ||
|
6bbb609f2f | ||
|
0d19902435 | ||
|
44bab83d68 | ||
|
42a4c1d60e | ||
|
645689e683 | ||
|
8b0153daf0 | ||
|
9ca1e259cb | ||
|
7227107d5e | ||
|
65ff00e28a | ||
|
717aa69d42 | ||
|
35fdb71f3d | ||
|
c33f70a8c6 | ||
|
0a3fdc404d | ||
|
efa7879c6d | ||
|
b11f22f517 | ||
|
9614275b34 | ||
|
9995876bc5 | ||
|
43a3991ddf | ||
|
27c24bc8a6 | ||
|
fac95dfec5 | ||
|
362542924e | ||
|
4179282244 | ||
|
02820ef2e9 | ||
|
0ecce7b93d | ||
|
f94fcd6f30 | ||
|
57f903630a | ||
|
9329de0a8d | ||
|
989648c21c | ||
|
0f0dcf9538 | ||
|
78e1a5b067 | ||
|
79404ec523 | ||
|
6c59a2f1b4 | ||
|
a295c86c05 | ||
|
a539f2f578 | ||
|
e710259611 | ||
|
f1d1ab7ed1 | ||
|
1934197fb7 | ||
|
e1c8757a10 | ||
|
768e9b589d | ||
|
582f17b330 | ||
|
23866a348d | ||
|
d0de306546 | ||
|
2af60d0a13 | ||
|
a8263afc24 | ||
|
a9943ab4f4 | ||
|
46a1eb8cce | ||
|
4517c0249f | ||
|
b538c13aad | ||
|
d3d98f9f54 | ||
|
1d5e09ef07 | ||
|
97a3a28d86 | ||
|
6ec765f2c4 | ||
|
54c7b4692d |
91
Makefile
Normal file
91
Makefile
Normal file
@@ -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:;
|
77
asnes/Makefile
Normal file
77
asnes/Makefile
Normal file
@@ -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
|
@@ -14,12 +14,7 @@ void Audio::coprocessor_enable(bool state) {
|
|||||||
|
|
||||||
void Audio::coprocessor_frequency(double input_frequency) {
|
void Audio::coprocessor_frequency(double input_frequency) {
|
||||||
double output_frequency;
|
double output_frequency;
|
||||||
if(system.region() == System::NTSC) {
|
output_frequency = system.apu_frequency() / 768.0;
|
||||||
output_frequency = config.smp.ntsc_clock_rate / 768.0;
|
|
||||||
} else /* (system.region() == System::PAL) */ {
|
|
||||||
output_frequency = config.smp.pal_clock_rate / 768.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_step = input_frequency / output_frequency;
|
r_step = input_frequency / output_frequency;
|
||||||
r_frac = 0;
|
r_frac = 0;
|
||||||
}
|
}
|
144
asnes/cartridge/cartridge.cpp
Normal file
144
asnes/cartridge/cartridge.cpp
Normal file
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
118
asnes/cartridge/cartridge.hpp
Normal file
118
asnes/cartridge/cartridge.hpp
Normal file
@@ -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;
|
37
asnes/cartridge/serialization.cpp
Normal file
37
asnes/cartridge/serialization.cpp
Normal file
@@ -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
|
671
asnes/cartridge/xml.cpp
Normal file
671
asnes/cartridge/xml.cpp
Normal file
@@ -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
|
2
asnes/cheat/cheat-inline.hpp
Normal file
2
asnes/cheat/cheat-inline.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bool Cheat::active() const { return cheat_enabled; }
|
||||||
|
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }
|
194
asnes/cheat/cheat.cpp
Normal file
194
asnes/cheat/cheat.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
asnes/cheat/cheat.hpp
Normal file
35
asnes/cheat/cheat.hpp
Normal file
@@ -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;
|
8
asnes/chip/bsx/bsx.cpp
Normal file
8
asnes/chip/bsx/bsx.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <snes.hpp>
|
||||||
|
|
||||||
|
#define BSX_CPP
|
||||||
|
namespace SNES {
|
||||||
|
#include "bsx_base.cpp"
|
||||||
|
#include "bsx_cart.cpp"
|
||||||
|
#include "bsx_flash.cpp"
|
||||||
|
}
|
@@ -6,7 +6,6 @@ void BSXCart::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BSXCart::enable() {
|
void BSXCart::enable() {
|
||||||
for(uint16 i = 0x5000; i <= 0x5fff; i++) memory::mmio.map(i, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSXCart::power() {
|
void BSXCart::power() {
|
||||||
@@ -26,39 +25,39 @@ void BSXCart::update_memory_map() {
|
|||||||
|
|
||||||
if((regs.r[0x02] & 0x80) == 0x00) {
|
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||||
//LoROM mapping
|
//LoROM mapping
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||||
bus.map(Bus::MapLinear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||||
} else {
|
} else {
|
||||||
//HiROM mapping
|
//HiROM mapping
|
||||||
bus.map(Bus::MapShadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||||
bus.map(Bus::MapLinear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||||
bus.map(Bus::MapShadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||||
bus.map(Bus::MapLinear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.r[0x03] & 0x80) {
|
if(regs.r[0x03] & 0x80) {
|
||||||
bus.map(Bus::MapLinear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
|
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
//bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((regs.r[0x05] & 0x80) == 0x00) {
|
if((regs.r[0x05] & 0x80) == 0x00) {
|
||||||
bus.map(Bus::MapLinear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
|
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((regs.r[0x06] & 0x80) == 0x00) {
|
if((regs.r[0x06] & 0x80) == 0x00) {
|
||||||
bus.map(Bus::MapLinear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
|
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.r[0x07] & 0x80) {
|
if(regs.r[0x07] & 0x80) {
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.r[0x08] & 0x80) {
|
if(regs.r[0x08] & 0x80) {
|
||||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.map(Bus::MapShadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
|
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
|
||||||
bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 BSXCart::mmio_read(unsigned addr) {
|
uint8 BSXCart::mmio_read(unsigned addr) {
|
@@ -60,7 +60,7 @@ void BSXFlash::write(unsigned addr, uint8 data) {
|
|||||||
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||||
//read-only flashcarts.
|
//read-only flashcarts.
|
||||||
//below is an unfortunately necessary workaround to this problem.
|
//below is an unfortunately necessary workaround to this problem.
|
||||||
if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
//if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
||||||
|
|
||||||
if((addr & 0xff0000) == 0) {
|
if((addr & 0xff0000) == 0) {
|
||||||
regs.write_old = regs.write_new;
|
regs.write_old = regs.write_new;
|
31
asnes/chip/chip.hpp
Normal file
31
asnes/chip/chip.hpp
Normal file
@@ -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);
|
||||||
|
}
|
@@ -4,7 +4,7 @@
|
|||||||
//Used in Rockman X2/X3 (Megaman X2/X3)
|
//Used in Rockman X2/X3 (Megaman X2/X3)
|
||||||
//Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
//Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||||
|
|
||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define CX4_CPP
|
#define CX4_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -21,8 +21,6 @@ void Cx4::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cx4::enable() {
|
void Cx4::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Cx4::ldr(uint8 r) {
|
uint32 Cx4::ldr(uint8 r) {
|
33
asnes/chip/dsp1/dsp1.cpp
Normal file
33
asnes/chip/dsp1/dsp1.cpp
Normal file
@@ -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) {}
|
||||||
|
|
||||||
|
}
|
@@ -1,20 +1,30 @@
|
|||||||
#include "dsp1emu.hpp"
|
#include "dsp1emu.hpp"
|
||||||
|
|
||||||
class DSP1 : public Memory {
|
class DSP1 {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
uint8 read(unsigned addr);
|
|
||||||
void write(unsigned addr, uint8 data);
|
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Dsp1 dsp1;
|
Dsp1 dsp1;
|
||||||
bool addr_decode(uint16 addr);
|
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 DSP1 dsp1;
|
||||||
|
extern DSP1DR dsp1dr;
|
||||||
|
extern DSP1SR dsp1sr;
|
@@ -1,9 +1,11 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define DSP2_CPP
|
#define DSP2_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
DSP2 dsp2;
|
DSP2 dsp2;
|
||||||
|
DSP2DR dsp2dr;
|
||||||
|
DSP2SR dsp2sr;
|
||||||
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
#include "opcodes.cpp"
|
#include "opcodes.cpp"
|
||||||
@@ -12,10 +14,6 @@ void DSP2::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DSP2::enable() {
|
void DSP2::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x20, 0x3f, 0x6000, 0x6fff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0x20, 0x3f, 0x8000, 0xbfff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0xa0, 0xbf, 0x6000, 0x6fff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0xa0, 0xbf, 0x8000, 0xbfff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSP2::power() {
|
void DSP2::power() {
|
||||||
@@ -145,5 +143,11 @@ void DSP2::write(unsigned addr, uint8 data) {
|
|||||||
|
|
||||||
DSP2::DSP2() {}
|
DSP2::DSP2() {}
|
||||||
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) {}
|
||||||
|
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
class DSP2 : public Memory {
|
class DSP2 {
|
||||||
public:
|
public:
|
||||||
struct {
|
struct {
|
||||||
bool waiting_for_command;
|
bool waiting_for_command;
|
||||||
@@ -42,4 +42,16 @@ protected:
|
|||||||
void op0d();
|
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 DSP2 dsp2;
|
||||||
|
extern DSP2DR dsp2dr;
|
||||||
|
extern DSP2SR dsp2sr;
|
@@ -1,4 +1,4 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define DSP3_CPP
|
#define DSP3_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -15,8 +15,6 @@ void DSP3::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DSP3::enable() {
|
void DSP3::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x20, 0x3f, 0x8000, 0xffff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0xa0, 0xbf, 0x8000, 0xffff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSP3::power() {
|
void DSP3::power() {
|
||||||
@@ -39,4 +37,4 @@ void DSP3::write(unsigned addr, uint8 data) {
|
|||||||
DSP3i::DSP3SetByte();
|
DSP3i::DSP3SetByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define DSP4_CPP
|
#define DSP4_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -9,8 +9,6 @@ void DSP4::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DSP4::enable() {
|
void DSP4::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x30, 0x3f, 0x8000, 0xffff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0xb0, 0xbf, 0x8000, 0xffff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace DSP4i {
|
namespace DSP4i {
|
||||||
@@ -59,4 +57,4 @@ void DSP4::write(unsigned addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
148
asnes/chip/msu1/msu1.cpp
Normal file
148
asnes/chip/msu1/msu1.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
asnes/chip/msu1/msu1.hpp
Normal file
39
asnes/chip/msu1/msu1.hpp
Normal file
@@ -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;
|
28
asnes/chip/msu1/serialization.cpp
Normal file
28
asnes/chip/msu1/serialization.cpp
Normal file
@@ -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
|
@@ -1,4 +1,4 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define OBC1_CPP
|
#define OBC1_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -11,8 +11,6 @@ void OBC1::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OBC1::enable() {
|
void OBC1::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBC1::power() {
|
void OBC1::power() {
|
||||||
@@ -81,4 +79,4 @@ void OBC1::ram_write(unsigned addr, uint8 data) {
|
|||||||
OBC1::OBC1() {}
|
OBC1::OBC1() {}
|
||||||
OBC1::~OBC1() {}
|
OBC1::~OBC1() {}
|
||||||
|
|
||||||
};
|
}
|
218
asnes/chip/sa1/bus/bus.cpp
Normal file
218
asnes/chip/sa1/bus/bus.cpp
Normal file
@@ -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
|
@@ -6,11 +6,10 @@ struct SA1Bus : Bus {
|
|||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VectorSelectionPage : Memory {
|
struct VSPROM : Memory {
|
||||||
|
unsigned size() const;
|
||||||
alwaysinline uint8 read(unsigned);
|
alwaysinline uint8 read(unsigned);
|
||||||
alwaysinline void write(unsigned, uint8);
|
alwaysinline void write(unsigned, uint8);
|
||||||
void sync();
|
|
||||||
Memory *access;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CPUIRAM : Memory {
|
struct CPUIRAM : Memory {
|
||||||
@@ -43,3 +42,14 @@ struct BitmapRAM : Memory {
|
|||||||
alwaysinline uint8 read(unsigned);
|
alwaysinline uint8 read(unsigned);
|
||||||
alwaysinline void write(unsigned, uint8);
|
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;
|
||||||
|
};
|
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
//BS-X flash carts, when present, are mapped to 0x400000+
|
//BS-X flash carts, when present, are mapped to 0x400000+
|
||||||
Memory& SA1::mmio_access(unsigned &addr) {
|
Memory& SA1::mmio_access(unsigned &addr) {
|
||||||
if(!memory::bsxflash.data()) return memory::cartrom;
|
if(!memory::bsxflash.data()) return memory::vsprom;
|
||||||
if(addr < 0x400000) return memory::cartrom;
|
if(addr < 0x400000) return memory::vsprom;
|
||||||
addr &= 0x3fffff;
|
addr &= 0x3fffff;
|
||||||
return bsxflash;
|
return bsxflash;
|
||||||
}
|
}
|
||||||
@@ -156,17 +156,15 @@ void SA1::mmio_w2220(uint8 data) {
|
|||||||
Memory &access = mmio_access(addr);
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
if(mmio.cbmode == 0) {
|
if(mmio.cbmode == 0) {
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom, 0x000000);
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||||
} else {
|
} else {
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||||
|
|
||||||
memory::vectorsp.sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//(DXB) Super MMC bank D
|
//(DXB) Super MMC bank D
|
||||||
@@ -178,15 +176,15 @@ void SA1::mmio_w2221(uint8 data) {
|
|||||||
Memory &access = mmio_access(addr);
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
if(mmio.dbmode == 0) {
|
if(mmio.dbmode == 0) {
|
||||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
|
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, memory::cartrom, 0x100000);
|
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||||
} else {
|
} else {
|
||||||
bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//(EXB) Super MMC bank E
|
//(EXB) Super MMC bank E
|
||||||
@@ -198,15 +196,15 @@ void SA1::mmio_w2222(uint8 data) {
|
|||||||
Memory &access = mmio_access(addr);
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
if(mmio.ebmode == 0) {
|
if(mmio.ebmode == 0) {
|
||||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom, 0x200000);
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||||
} else {
|
} else {
|
||||||
bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//(FXB) Super MMC bank F
|
//(FXB) Super MMC bank F
|
||||||
@@ -218,23 +216,23 @@ void SA1::mmio_w2223(uint8 data) {
|
|||||||
Memory &access = mmio_access(addr);
|
Memory &access = mmio_access(addr);
|
||||||
|
|
||||||
if(mmio.fbmode == 0) {
|
if(mmio.fbmode == 0) {
|
||||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
|
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, memory::cartrom, 0x300000);
|
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||||
} else {
|
} else {
|
||||||
bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||||
sa1bus.map(Bus::MapLinear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
sa1bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//(BMAPS) S-CPU BW-RAM address mapping
|
//(BMAPS) S-CPU BW-RAM address mapping
|
||||||
void SA1::mmio_w2224(uint8 data) {
|
void SA1::mmio_w2224(uint8 data) {
|
||||||
mmio.sbm = (data & 0x1f);
|
mmio.sbm = (data & 0x1f);
|
||||||
|
|
||||||
bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||||
bus.map(Bus::MapLinear, 0x80, 0xbf, 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
|
//(BMAP) SA-1 BW-RAM address mapping
|
||||||
@@ -244,12 +242,12 @@ void SA1::mmio_w2225(uint8 data) {
|
|||||||
|
|
||||||
if(mmio.sw46 == 0) {
|
if(mmio.sw46 == 0) {
|
||||||
//$[40-43]:[0000-ffff] x 32 projection
|
//$[40-43]:[0000-ffff] x 32 projection
|
||||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 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 {
|
} else {
|
||||||
//$[60-6f]:[0000-ffff] x 128 projection
|
//$[60-6f]:[0000-ffff] x 128 projection
|
||||||
sa1bus.map(Bus::MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||||
sa1bus.map(Bus::MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,7 +521,7 @@ uint8 SA1::mmio_r230e() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8 SA1::mmio_read(unsigned addr) {
|
uint8 SA1::mmio_read(unsigned addr) {
|
||||||
(co_active() == scheduler.thread_cpu ? scheduler.sync_cpucop() : scheduler.sync_copcpu());
|
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
@@ -548,7 +546,7 @@ uint8 SA1::mmio_read(unsigned addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SA1::mmio_write(unsigned addr, uint8 data) {
|
void SA1::mmio_write(unsigned addr, uint8 data) {
|
||||||
(co_active() == scheduler.thread_cpu ? scheduler.sync_cpucop() : scheduler.sync_copcpu());
|
(co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu());
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
@@ -1,21 +1,29 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define SA1_CPP
|
#define SA1_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
SA1 sa1;
|
SA1 sa1;
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
#include "bus/bus.cpp"
|
#include "bus/bus.cpp"
|
||||||
#include "dma/dma.cpp"
|
#include "dma/dma.cpp"
|
||||||
#include "memory/memory.cpp"
|
#include "memory/memory.cpp"
|
||||||
#include "mmio/mmio.cpp"
|
#include "mmio/mmio.cpp"
|
||||||
|
|
||||||
|
void SA1::Enter() { sa1.enter(); }
|
||||||
|
|
||||||
void SA1::enter() {
|
void SA1::enter() {
|
||||||
while(true) {
|
while(true) {
|
||||||
while(mmio.sa1_rdyb || mmio.sa1_resb) {
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||||
//SA-1 co-processor is asleep
|
//SA-1 co-processor is asleep
|
||||||
tick();
|
tick();
|
||||||
scheduler.sync_copcpu();
|
synchronize_cpu();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(status.interrupt_pending) {
|
if(status.interrupt_pending) {
|
||||||
@@ -55,8 +63,8 @@ void SA1::last_cycle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SA1::interrupt(uint16 vector) {
|
void SA1::interrupt(uint16 vector) {
|
||||||
op_read(regs.pc.d);
|
SA1::op_read(regs.pc.d);
|
||||||
op_io();
|
SA1::op_io();
|
||||||
if(!regs.e) op_writestack(regs.pc.b);
|
if(!regs.e) op_writestack(regs.pc.b);
|
||||||
op_writestack(regs.pc.h);
|
op_writestack(regs.pc.h);
|
||||||
op_writestack(regs.pc.l);
|
op_writestack(regs.pc.l);
|
||||||
@@ -72,8 +80,8 @@ bool SA1::interrupt_pending() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SA1::tick() {
|
void SA1::tick() {
|
||||||
scheduler.addclocks_cop(2);
|
step(2);
|
||||||
if(++status.tick_counter == 0) scheduler.sync_copcpu();
|
if(++status.tick_counter == 0) synchronize_cpu();
|
||||||
|
|
||||||
//adjust counters:
|
//adjust counters:
|
||||||
//note that internally, status counters are in clocks;
|
//note that internally, status counters are in clocks;
|
||||||
@@ -116,18 +124,18 @@ void SA1::enable() {
|
|||||||
void SA1::power() {
|
void SA1::power() {
|
||||||
regs.a = regs.x = regs.y = 0x0000;
|
regs.a = regs.x = regs.y = 0x0000;
|
||||||
regs.s = 0x01ff;
|
regs.s = 0x01ff;
|
||||||
|
vbrbus.init();
|
||||||
|
sa1bus.init();
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SA1::reset() {
|
void SA1::reset() {
|
||||||
memory::vectorsp.access = 0;
|
create(SA1::Enter, system.cpu_frequency());
|
||||||
|
|
||||||
memory::cc1bwram.dma = false;
|
memory::cc1bwram.dma = false;
|
||||||
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
|
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
|
||||||
memory::iram.write(addr, 0x00);
|
memory::iram.write(addr, 0x00);
|
||||||
}
|
}
|
||||||
vbrbus.init();
|
|
||||||
sa1bus.init();
|
|
||||||
|
|
||||||
regs.pc.d = 0x000000;
|
regs.pc.d = 0x000000;
|
||||||
regs.x.h = 0x00;
|
regs.x.h = 0x00;
|
||||||
@@ -139,14 +147,14 @@ void SA1::reset() {
|
|||||||
regs.e = 1;
|
regs.e = 1;
|
||||||
regs.mdr = 0x00;
|
regs.mdr = 0x00;
|
||||||
regs.wai = false;
|
regs.wai = false;
|
||||||
update_table();
|
CPUcore::update_table();
|
||||||
|
|
||||||
status.tick_counter = 0;
|
status.tick_counter = 0;
|
||||||
|
|
||||||
status.interrupt_pending = false;
|
status.interrupt_pending = false;
|
||||||
status.interrupt_vector = 0x0000;
|
status.interrupt_vector = 0x0000;
|
||||||
|
|
||||||
status.scanlines = (system.region() == System::NTSC ? 262 : 312);
|
status.scanlines = (system.region() == System::Region::NTSC ? 262 : 312);
|
||||||
status.vcounter = 0;
|
status.vcounter = 0;
|
||||||
status.hcounter = 0;
|
status.hcounter = 0;
|
||||||
|
|
||||||
@@ -318,4 +326,4 @@ void SA1::reset() {
|
|||||||
SA1::SA1() {
|
SA1::SA1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
#include "bus/bus.hpp"
|
#include "bus/bus.hpp"
|
||||||
|
|
||||||
class SA1 : public CPUcore, public MMIO {
|
class SA1 : public Coprocessor, public CPUcore, public MMIO {
|
||||||
public:
|
public:
|
||||||
#include "dma/dma.hpp"
|
#include "dma/dma.hpp"
|
||||||
#include "memory/memory.hpp"
|
#include "memory/memory.hpp"
|
||||||
@@ -17,6 +17,7 @@ public:
|
|||||||
uint16 hcounter;
|
uint16 hcounter;
|
||||||
} status;
|
} status;
|
||||||
|
|
||||||
|
static void Enter();
|
||||||
void enter();
|
void enter();
|
||||||
void interrupt(uint16 vector);
|
void interrupt(uint16 vector);
|
||||||
void tick();
|
void tick();
|
||||||
@@ -30,6 +31,7 @@ public:
|
|||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
SA1();
|
SA1();
|
||||||
};
|
};
|
||||||
|
|
149
asnes/chip/sa1/serialization.cpp
Normal file
149
asnes/chip/sa1/serialization.cpp
Normal file
@@ -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
|
@@ -1,4 +1,4 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define SDD1_CPP
|
#define SDD1_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -17,11 +17,6 @@ void SDD1::enable() {
|
|||||||
cpu_mmio[i & 0x7f] = memory::mmio.mmio[i - 0x2000];
|
cpu_mmio[i & 0x7f] = memory::mmio.mmio[i - 0x2000];
|
||||||
memory::mmio.map(i, *this);
|
memory::mmio.map(i, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//hook S-DD1 MMIO registers
|
|
||||||
for(unsigned i = 0x4800; i <= 0x4807; i++) {
|
|
||||||
memory::mmio.map(i, *this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDD1::power() {
|
void SDD1::power() {
|
||||||
@@ -43,8 +38,6 @@ void SDD1::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer.ready = false;
|
buffer.ready = false;
|
||||||
|
|
||||||
bus.map(Bus::MapDirect, 0xc0, 0xff, 0x0000, 0xffff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SDD1::mmio_read(unsigned addr) {
|
uint8 SDD1::mmio_read(unsigned addr) {
|
||||||
@@ -55,10 +48,10 @@ uint8 SDD1::mmio_read(unsigned addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0x4804: return (mmc[0] >> 20) & 7;
|
case 0x4804: return mmc[0] >> 20;
|
||||||
case 0x4805: return (mmc[1] >> 20) & 7;
|
case 0x4805: return mmc[1] >> 20;
|
||||||
case 0x4806: return (mmc[2] >> 20) & 7;
|
case 0x4806: return mmc[2] >> 20;
|
||||||
case 0x4807: return (mmc[3] >> 20) & 7;
|
case 0x4807: return mmc[3] >> 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return cpu.regs.mdr;
|
||||||
@@ -84,10 +77,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
|||||||
case 0x4800: sdd1_enable = data; break;
|
case 0x4800: sdd1_enable = data; break;
|
||||||
case 0x4801: xfer_enable = data; break;
|
case 0x4801: xfer_enable = data; break;
|
||||||
|
|
||||||
case 0x4804: mmc[0] = (data & 7) << 20; break;
|
case 0x4804: mmc[0] = data << 20; break;
|
||||||
case 0x4805: mmc[1] = (data & 7) << 20; break;
|
case 0x4805: mmc[1] = data << 20; break;
|
||||||
case 0x4806: mmc[2] = (data & 7) << 20; break;
|
case 0x4806: mmc[2] = data << 20; break;
|
||||||
case 0x4807: mmc[3] = (data & 7) << 20; break;
|
case 0x4807: mmc[3] = data << 20; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,4 +151,4 @@ SDD1::SDD1() {
|
|||||||
SDD1::~SDD1() {
|
SDD1::~SDD1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
97
asnes/chip/serial/serial.cpp
Normal file
97
asnes/chip/serial/serial.cpp
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
asnes/chip/serial/serial.hpp
Normal file
25
asnes/chip/serial/serial.hpp
Normal file
@@ -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;
|
8
asnes/chip/serial/serialization.cpp
Normal file
8
asnes/chip/serial/serialization.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifdef SERIAL_CPP
|
||||||
|
|
||||||
|
void Serial::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
s.integer((bool&)latch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -24,9 +24,9 @@ void SPC7110Decomp::write(uint8 data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8 SPC7110Decomp::dataread() {
|
uint8 SPC7110Decomp::dataread() {
|
||||||
unsigned size = memory::cartrom.size() - 0x100000;
|
unsigned size = memory::cartrom.size() - cartridge.spc7110_data_rom_offset();
|
||||||
while(decomp_offset >= size) decomp_offset -= size;
|
while(decomp_offset >= size) decomp_offset -= size;
|
||||||
return memory::cartrom.read(0x100000 + decomp_offset++);
|
return memory::cartrom.read(cartridge.spc7110_data_rom_offset() + decomp_offset++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
@@ -1,9 +1,12 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define SPC7110_CPP
|
#define SPC7110_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
SPC7110 spc7110;
|
SPC7110 spc7110;
|
||||||
|
SPC7110MCU spc7110mcu;
|
||||||
|
SPC7110DCU spc7110dcu;
|
||||||
|
SPC7110RAM spc7110ram;
|
||||||
|
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
#include "decomp.cpp"
|
#include "decomp.cpp"
|
||||||
@@ -11,11 +14,7 @@ SPC7110 spc7110;
|
|||||||
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
void SPC7110::init() {}
|
void SPC7110::init() {}
|
||||||
|
void SPC7110::enable() {}
|
||||||
void SPC7110::enable() {
|
|
||||||
uint16_t limit = (cartridge.has_spc7110rtc() ? 0x4842 : 0x483f);
|
|
||||||
for(uint16_t i = 0x4800; i <= limit; i++) memory::mmio.map(i, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPC7110::power() {
|
void SPC7110::power() {
|
||||||
reset();
|
reset();
|
||||||
@@ -85,9 +84,9 @@ void SPC7110::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned SPC7110::datarom_addr(unsigned addr) {
|
unsigned SPC7110::datarom_addr(unsigned addr) {
|
||||||
unsigned size = memory::cartrom.size() - 0x100000;
|
unsigned size = memory::cartrom.size() - cartridge.spc7110_data_rom_offset();
|
||||||
while(addr >= size) addr -= size;
|
while(addr >= size) addr -= size;
|
||||||
return addr + 0x100000;
|
return cartridge.spc7110_data_rom_offset() + addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
|
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
|
||||||
@@ -535,17 +534,17 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
|||||||
|
|
||||||
case 0x4831: {
|
case 0x4831: {
|
||||||
r4831 = data;
|
r4831 = data;
|
||||||
dx_offset = datarom_addr((data & 7) * 0x100000);
|
dx_offset = datarom_addr(data * 0x100000);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x4832: {
|
case 0x4832: {
|
||||||
r4832 = data;
|
r4832 = data;
|
||||||
ex_offset = datarom_addr((data & 7) * 0x100000);
|
ex_offset = datarom_addr(data * 0x100000);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x4833: {
|
case 0x4833: {
|
||||||
r4833 = data;
|
r4833 = data;
|
||||||
fx_offset = datarom_addr((data & 7) * 0x100000);
|
fx_offset = datarom_addr(data * 0x100000);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x4834: r4834 = data; break;
|
case 0x4834: r4834 = data; break;
|
||||||
@@ -632,46 +631,52 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SPC7110::read(unsigned addr) {
|
|
||||||
//$[00-0f|80-8f]:[8000-ffff], $[c0-cf]:[0000-ffff] mapped directly to memory::cartrom
|
|
||||||
|
|
||||||
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
|
||||||
//$[00|30]:[6000-7fff]
|
|
||||||
return memory::cartram.read(addr & 0x1fff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((addr & 0xff0000) == 0x500000) {
|
|
||||||
//$[50]:[0000-ffff]
|
|
||||||
return mmio_read(0x4800);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0xd00000) {
|
|
||||||
//$[d0-df]:[0000-ffff]
|
|
||||||
return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0xe00000) {
|
|
||||||
//$[e0-ef]:[0000-ffff]
|
|
||||||
return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0xf00000) {
|
|
||||||
//$[f0-ff]:[0000-ffff]
|
|
||||||
return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPC7110::write(unsigned addr, uint8 data) {
|
|
||||||
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
|
||||||
//$[00|30]:[6000-7fff]
|
|
||||||
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SPC7110::SPC7110() {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
/*****
|
/*****
|
||||||
* SPC7110 emulator - version 0.03 (2008-08-10)
|
* SPC7110 emulator - version 0.04 (2010-02-14)
|
||||||
* Copyright (c) 2008, byuu and neviksti
|
* Copyright (c) 2008-2010, byuu and neviksti
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "decomp.hpp"
|
#include "decomp.hpp"
|
||||||
|
|
||||||
class SPC7110 : public MMIO, public Memory {
|
class SPC7110 : public MMIO {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
@@ -38,9 +38,6 @@ public:
|
|||||||
uint8 mmio_read(unsigned addr);
|
uint8 mmio_read(unsigned addr);
|
||||||
void mmio_write(unsigned addr, uint8 data);
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
uint8 read(unsigned addr);
|
|
||||||
void write(unsigned addr, uint8 data);
|
|
||||||
|
|
||||||
//spc7110decomp
|
//spc7110decomp
|
||||||
void decomp_init();
|
void decomp_init();
|
||||||
uint8 decomp_read();
|
uint8 decomp_read();
|
||||||
@@ -131,6 +128,32 @@ private:
|
|||||||
unsigned rtc_index;
|
unsigned rtc_index;
|
||||||
|
|
||||||
static const unsigned months[12];
|
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 SPC7110 spc7110;
|
||||||
|
extern SPC7110MCU spc7110mcu;
|
||||||
|
extern SPC7110DCU spc7110dcu;
|
||||||
|
extern SPC7110RAM spc7110ram;
|
@@ -1,4 +1,4 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define SRTC_CPP
|
#define SRTC_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
@@ -13,8 +13,6 @@ void SRTC::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SRTC::enable() {
|
void SRTC::enable() {
|
||||||
memory::mmio.map(0x2800, *this);
|
|
||||||
memory::mmio.map(0x2801, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SRTC::power() {
|
void SRTC::power() {
|
||||||
@@ -230,4 +228,4 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
|
|||||||
SRTC::SRTC() {
|
SRTC::SRTC() {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,4 +1,6 @@
|
|||||||
const int16 ST010::sin_table[256] = {
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
|
const int16 ST0010::sin_table[256] = {
|
||||||
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
|
||||||
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
||||||
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
||||||
@@ -33,7 +35,7 @@ const int16 ST010::sin_table[256] = {
|
|||||||
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
-0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
|
||||||
};
|
};
|
||||||
|
|
||||||
const int16 ST010::mode7_scale[176] = {
|
const int16 ST0010::mode7_scale[176] = {
|
||||||
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
|
||||||
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
|
||||||
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
|
||||||
@@ -58,7 +60,7 @@ const int16 ST010::mode7_scale[176] = {
|
|||||||
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8 ST010::arctan[32][32] = {
|
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, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
|
||||||
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
{ 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
|
||||||
@@ -124,3 +126,5 @@ const uint8 ST010::arctan[32][32] = {
|
|||||||
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
{ 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
|
||||||
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -1,9 +1,9 @@
|
|||||||
#ifdef ST010_CPP
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
//ST-010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
//ST-0010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
|
||||||
//bsnes port - Copyright (C) 2007 byuu
|
//bsnes port - Copyright (C) 2007 byuu
|
||||||
|
|
||||||
void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
|
void ST0010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
|
||||||
if((x0 < 0) && (y0 < 0)) {
|
if((x0 < 0) && (y0 < 0)) {
|
||||||
x1 = -x0;
|
x1 = -x0;
|
||||||
y1 = -y0;
|
y1 = -y0;
|
||||||
@@ -34,7 +34,7 @@ void ST010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
void ST010::op_01() {
|
void ST0010::op_01() {
|
||||||
int16 x0 = readw(0x0000);
|
int16 x0 = readw(0x0000);
|
||||||
int16 y0 = readw(0x0002);
|
int16 y0 = readw(0x0002);
|
||||||
int16 x1, y1, quadrant, theta;
|
int16 x1, y1, quadrant, theta;
|
||||||
@@ -48,7 +48,7 @@ void ST010::op_01() {
|
|||||||
writew(0x0010, theta);
|
writew(0x0010, theta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_02() {
|
void ST0010::op_02() {
|
||||||
int16 positions = readw(0x0024);
|
int16 positions = readw(0x0024);
|
||||||
uint16 *places = (uint16*)(ram + 0x0040);
|
uint16 *places = (uint16*)(ram + 0x0040);
|
||||||
uint16 *drivers = (uint16*)(ram + 0x0080);
|
uint16 *drivers = (uint16*)(ram + 0x0080);
|
||||||
@@ -76,7 +76,7 @@ void ST010::op_02() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_03() {
|
void ST0010::op_03() {
|
||||||
int16 x0 = readw(0x0000);
|
int16 x0 = readw(0x0000);
|
||||||
int16 y0 = readw(0x0002);
|
int16 y0 = readw(0x0002);
|
||||||
int16 multiplier = readw(0x0004);
|
int16 multiplier = readw(0x0004);
|
||||||
@@ -89,7 +89,7 @@ void ST010::op_03() {
|
|||||||
writed(0x0014, y1);
|
writed(0x0014, y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_04() {
|
void ST0010::op_04() {
|
||||||
int16 x = readw(0x0000);
|
int16 x = readw(0x0000);
|
||||||
int16 y = readw(0x0002);
|
int16 y = readw(0x0002);
|
||||||
int16 square;
|
int16 square;
|
||||||
@@ -99,7 +99,7 @@ void ST010::op_04() {
|
|||||||
writew(0x0010, square);
|
writew(0x0010, square);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_05() {
|
void ST0010::op_05() {
|
||||||
int32 dx, dy;
|
int32 dx, dy;
|
||||||
int16 a1, b1, c1;
|
int16 a1, b1, c1;
|
||||||
uint16 o1;
|
uint16 o1;
|
||||||
@@ -217,7 +217,7 @@ void ST010::op_05() {
|
|||||||
writew(0x00dc, flags);
|
writew(0x00dc, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_06() {
|
void ST0010::op_06() {
|
||||||
int16 multiplicand = readw(0x0000);
|
int16 multiplicand = readw(0x0000);
|
||||||
int16 multiplier = readw(0x0002);
|
int16 multiplier = readw(0x0002);
|
||||||
int32 product;
|
int32 product;
|
||||||
@@ -227,7 +227,7 @@ void ST010::op_06() {
|
|||||||
writed(0x0010, product);
|
writed(0x0010, product);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_07() {
|
void ST0010::op_07() {
|
||||||
int16 theta = readw(0x0000);
|
int16 theta = readw(0x0000);
|
||||||
|
|
||||||
int16 data;
|
int16 data;
|
||||||
@@ -245,7 +245,7 @@ void ST010::op_07() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::op_08() {
|
void ST0010::op_08() {
|
||||||
int16 x0 = readw(0x0000);
|
int16 x0 = readw(0x0000);
|
||||||
int16 y0 = readw(0x0002);
|
int16 y0 = readw(0x0002);
|
||||||
int16 theta = readw(0x0004);
|
int16 theta = readw(0x0004);
|
7
asnes/chip/st0010/serialization.cpp
Normal file
7
asnes/chip/st0010/serialization.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifdef ST0010_CPP
|
||||||
|
|
||||||
|
void ST0010::serialize(serializer &s) {
|
||||||
|
s.array(ram);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -1,56 +1,54 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define ST010_CPP
|
#define ST0010_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
ST010 st010;
|
ST0010 st0010;
|
||||||
|
|
||||||
#include "st010_data.hpp"
|
#include "data.hpp"
|
||||||
|
#include "opcodes.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
#include "st010_op.cpp"
|
|
||||||
|
|
||||||
void ST010::init() {
|
void ST0010::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::enable() {
|
void ST0010::enable() {
|
||||||
bus.map(Bus::MapDirect, 0x68, 0x6f, 0x0000, 0x0fff, *this);
|
|
||||||
bus.map(Bus::MapDirect, 0xe8, 0xef, 0x0000, 0x0fff, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 ST010::sin(int16 theta) {
|
int16 ST0010::sin(int16 theta) {
|
||||||
return sin_table[(theta >> 8) & 0xff];
|
return sin_table[(theta >> 8) & 0xff];
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 ST010::cos(int16 theta) {
|
int16 ST0010::cos(int16 theta) {
|
||||||
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
return sin_table[((theta + 0x4000) >> 8) & 0xff];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 ST010::readb(uint16 addr) {
|
uint8 ST0010::readb(uint16 addr) {
|
||||||
return ram[addr & 0xfff];
|
return ram[addr & 0xfff];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 ST010::readw(uint16 addr) {
|
uint16 ST0010::readw(uint16 addr) {
|
||||||
return (readb(addr + 0) << 0) |
|
return (readb(addr + 0) << 0) |
|
||||||
(readb(addr + 1) << 8);
|
(readb(addr + 1) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ST010::readd(uint16 addr) {
|
uint32 ST0010::readd(uint16 addr) {
|
||||||
return (readb(addr + 0) << 0) |
|
return (readb(addr + 0) << 0) |
|
||||||
(readb(addr + 1) << 8) |
|
(readb(addr + 1) << 8) |
|
||||||
(readb(addr + 2) << 16) |
|
(readb(addr + 2) << 16) |
|
||||||
(readb(addr + 3) << 24);
|
(readb(addr + 3) << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::writeb(uint16 addr, uint8 data) {
|
void ST0010::writeb(uint16 addr, uint8 data) {
|
||||||
ram[addr & 0xfff] = data;
|
ram[addr & 0xfff] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::writew(uint16 addr, uint16 data) {
|
void ST0010::writew(uint16 addr, uint16 data) {
|
||||||
writeb(addr + 0, data >> 0);
|
writeb(addr + 0, data >> 0);
|
||||||
writeb(addr + 1, data >> 8);
|
writeb(addr + 1, data >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::writed(uint16 addr, uint32 data) {
|
void ST0010::writed(uint16 addr, uint32 data) {
|
||||||
writeb(addr + 0, data >> 0);
|
writeb(addr + 0, data >> 0);
|
||||||
writeb(addr + 1, data >> 8);
|
writeb(addr + 1, data >> 8);
|
||||||
writeb(addr + 2, data >> 16);
|
writeb(addr + 2, data >> 16);
|
||||||
@@ -59,21 +57,21 @@ void ST010::writed(uint16 addr, uint32 data) {
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
void ST010::power() {
|
void ST0010::power() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::reset() {
|
void ST0010::reset() {
|
||||||
memset(ram, 0x00, sizeof ram);
|
memset(ram, 0x00, sizeof ram);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
uint8 ST010::read(unsigned addr) {
|
uint8 ST0010::read(unsigned addr) {
|
||||||
return readb(addr);
|
return readb(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST010::write(unsigned addr, uint8 data) {
|
void ST0010::write(unsigned addr, uint8 data) {
|
||||||
writeb(addr, data);
|
writeb(addr, data);
|
||||||
|
|
||||||
if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
|
if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
|
||||||
@@ -92,4 +90,4 @@ void ST010::write(unsigned addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
class ST010 : public Memory {
|
class ST0010 : public Memory {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
@@ -41,4 +41,4 @@ private:
|
|||||||
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ST010 st010;
|
extern ST0010 st0010;
|
20
asnes/chip/st0011/st0011.cpp
Normal file
20
asnes/chip/st0011/st0011.cpp
Normal file
@@ -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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
class ST011 {
|
class ST0011 {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
@@ -6,4 +6,4 @@ public:
|
|||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ST011 st011;
|
extern ST0011 st0011;
|
@@ -1,18 +1,18 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define ST018_CPP
|
#define ST0018_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
ST018 st018;
|
ST0018 st0018;
|
||||||
|
|
||||||
uint8 ST018::mmio_read(unsigned addr) {
|
uint8 ST0018::mmio_read(unsigned addr) {
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
if(addr == 0x3800) return regs.r3800;
|
if(addr == 0x3800) return regs.r3800;
|
||||||
if(addr == 0x3804) return regs.r3804;
|
if(addr == 0x3804) return regs.r3804;
|
||||||
return cpu.regs.mdr;
|
return cpu.regs.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::mmio_write(unsigned addr, uint8 data) {
|
void ST0018::mmio_write(unsigned addr, uint8 data) {
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
if(addr == 0x3802) {
|
if(addr == 0x3802) {
|
||||||
@@ -45,18 +45,17 @@ void ST018::mmio_write(unsigned addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::init() {
|
void ST0018::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::enable() {
|
void ST0018::enable() {
|
||||||
for(unsigned i = 0x3800; i <= 0x38ff; i++) memory::mmio.map(i, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::power() {
|
void ST0018::power() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::reset() {
|
void ST0018::reset() {
|
||||||
regs.mode = Waiting;
|
regs.mode = Waiting;
|
||||||
regs.r3800 = 0x00;
|
regs.r3800 = 0x00;
|
||||||
regs.r3804 = 0x85;
|
regs.r3804 = 0x85;
|
||||||
@@ -64,17 +63,17 @@ void ST018::reset() {
|
|||||||
for(unsigned i = 0; i < 97; i++) board[i] = 0;
|
for(unsigned i = 0; i < 97; i++) board[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============
|
//===============
|
||||||
//ST018 opcodes
|
//ST-0018 opcodes
|
||||||
//=============
|
//===============
|
||||||
|
|
||||||
void ST018::op_board_upload() {
|
void ST0018::op_board_upload() {
|
||||||
regs.mode = BoardUpload;
|
regs.mode = BoardUpload;
|
||||||
regs.counter = 0;
|
regs.counter = 0;
|
||||||
regs.r3800 = 0xe0;
|
regs.r3800 = 0xe0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_board_upload(uint8 data) {
|
void ST0018::op_board_upload(uint8 data) {
|
||||||
board[regs.counter] = data;
|
board[regs.counter] = data;
|
||||||
regs.r3800 = 96 - regs.counter;
|
regs.r3800 = 96 - regs.counter;
|
||||||
regs.counter++;
|
regs.counter++;
|
||||||
@@ -93,32 +92,32 @@ void ST018::op_board_upload(uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_b2() {
|
void ST0018::op_b2() {
|
||||||
fprintf(stdout, "* ST018 w3802::b2\n");
|
fprintf(stdout, "* ST018 w3802::b2\n");
|
||||||
regs.r3800 = 0xe0;
|
regs.r3800 = 0xe0;
|
||||||
regs.r3800_01 = 0; //unknown
|
regs.r3800_01 = 0; //unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_b3() {
|
void ST0018::op_b3() {
|
||||||
fprintf(stdout, "* ST018 w3802::b3\n");
|
fprintf(stdout, "* ST018 w3802::b3\n");
|
||||||
regs.r3800 = 0xe0;
|
regs.r3800 = 0xe0;
|
||||||
regs.r3800_01 = 1; //0 = player lost?
|
regs.r3800_01 = 1; //0 = player lost?
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_b4() {
|
void ST0018::op_b4() {
|
||||||
fprintf(stdout, "* ST018 w3802::b4\n");
|
fprintf(stdout, "* ST018 w3802::b4\n");
|
||||||
regs.r3800 = 0xe0;
|
regs.r3800 = 0xe0;
|
||||||
regs.r3800_01 = 1; //0 = player won?
|
regs.r3800_01 = 1; //0 = player won?
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_b5() {
|
void ST0018::op_b5() {
|
||||||
fprintf(stdout, "* ST018 w3802::b5\n");
|
fprintf(stdout, "* ST018 w3802::b5\n");
|
||||||
regs.r3800 = 0xe0;
|
regs.r3800 = 0xe0;
|
||||||
regs.r3800_01 = 0; //1 = move will result in checkmate?
|
regs.r3800_01 = 0; //1 = move will result in checkmate?
|
||||||
}
|
}
|
||||||
|
|
||||||
void ST018::op_query_chip() {
|
void ST0018::op_query_chip() {
|
||||||
regs.r3800 = 0x00;
|
regs.r3800 = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
class ST018 : public MMIO {
|
class ST0018 : public MMIO {
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
@@ -48,4 +48,4 @@ private:
|
|||||||
void op_query_chip();
|
void op_query_chip();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ST018 st018;
|
extern ST0018 st0018;
|
@@ -3,28 +3,19 @@
|
|||||||
SuperFXBus superfxbus;
|
SuperFXBus superfxbus;
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
static SuperFXGSUROM gsurom;
|
SuperFXGSUROM gsurom;
|
||||||
static SuperFXGSURAM gsuram;
|
SuperFXGSURAM gsuram;
|
||||||
static SuperFXCPUROM fxrom;
|
SuperFXCPUROM fxrom;
|
||||||
static SuperFXCPURAM fxram;
|
SuperFXCPURAM fxram;
|
||||||
};
|
}
|
||||||
|
|
||||||
void SuperFXBus::init() {
|
void SuperFXBus::init() {
|
||||||
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||||
|
|
||||||
map(MapLinear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
|
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
|
||||||
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
|
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
|
||||||
map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
|
map(MapMode::Linear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
|
||||||
map(MapLinear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
|
map(MapMode::Linear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
|
||||||
|
|
||||||
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
|
|
||||||
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::fxrom);
|
|
||||||
bus.map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::fxrom);
|
|
||||||
bus.map(MapLinear, 0x60, 0x7d, 0x0000, 0xffff, memory::fxram);
|
|
||||||
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
|
|
||||||
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::fxrom);
|
|
||||||
bus.map(MapLinear, 0xc0, 0xdf, 0x0000, 0xffff, memory::fxrom);
|
|
||||||
bus.map(MapLinear, 0xe0, 0xff, 0x0000, 0xffff, memory::fxram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//ROM / RAM access from the SuperFX CPU
|
//ROM / RAM access from the SuperFX CPU
|
||||||
@@ -34,17 +25,17 @@ unsigned SuperFXGSUROM::size() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8 SuperFXGSUROM::read(unsigned addr) {
|
uint8 SuperFXGSUROM::read(unsigned addr) {
|
||||||
while(!superfx.regs.scmr.ron) {
|
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
superfx.add_clocks(6);
|
superfx.add_clocks(6);
|
||||||
scheduler.sync_copcpu();
|
superfx.synchronize_cpu();
|
||||||
}
|
}
|
||||||
return memory::cartrom.read(addr);
|
return memory::cartrom.read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
|
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
|
||||||
while(!superfx.regs.scmr.ron) {
|
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
superfx.add_clocks(6);
|
superfx.add_clocks(6);
|
||||||
scheduler.sync_copcpu();
|
superfx.synchronize_cpu();
|
||||||
}
|
}
|
||||||
memory::cartrom.write(addr, data);
|
memory::cartrom.write(addr, data);
|
||||||
}
|
}
|
||||||
@@ -54,17 +45,17 @@ unsigned SuperFXGSURAM::size() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8 SuperFXGSURAM::read(unsigned addr) {
|
uint8 SuperFXGSURAM::read(unsigned addr) {
|
||||||
while(!superfx.regs.scmr.ran) {
|
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
superfx.add_clocks(6);
|
superfx.add_clocks(6);
|
||||||
scheduler.sync_copcpu();
|
superfx.synchronize_cpu();
|
||||||
}
|
}
|
||||||
return memory::cartram.read(addr);
|
return memory::cartram.read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
|
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
|
||||||
while(!superfx.regs.scmr.ran) {
|
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
superfx.add_clocks(6);
|
superfx.add_clocks(6);
|
||||||
scheduler.sync_copcpu();
|
superfx.synchronize_cpu();
|
||||||
}
|
}
|
||||||
memory::cartram.write(addr, data);
|
memory::cartram.write(addr, data);
|
||||||
}
|
}
|
@@ -25,3 +25,10 @@ struct SuperFXCPURAM : Memory {
|
|||||||
uint8 read(unsigned);
|
uint8 read(unsigned);
|
||||||
void write(unsigned, uint8);
|
void write(unsigned, uint8);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace memory {
|
||||||
|
extern SuperFXGSUROM gsurom;
|
||||||
|
extern SuperFXGSURAM gsuram;
|
||||||
|
extern SuperFXCPUROM fxrom;
|
||||||
|
extern SuperFXCPURAM fxram;
|
||||||
|
}
|
@@ -114,7 +114,7 @@ void SuperFX::op_bvs() {
|
|||||||
//$10-1f(b1): move rN
|
//$10-1f(b1): move rN
|
||||||
template<int n> void SuperFX::op_to_r() {
|
template<int n> void SuperFX::op_to_r() {
|
||||||
if(regs.sfr.b == 0) {
|
if(regs.sfr.b == 0) {
|
||||||
regs.dreg = ®s.r[n];
|
regs.dreg = n;
|
||||||
} else {
|
} else {
|
||||||
regs.r[n] = regs.sr();
|
regs.r[n] = regs.sr();
|
||||||
regs.reset();
|
regs.reset();
|
||||||
@@ -123,8 +123,8 @@ template<int n> void SuperFX::op_to_r() {
|
|||||||
|
|
||||||
//$20-2f: with rN
|
//$20-2f: with rN
|
||||||
template<int n> void SuperFX::op_with_r() {
|
template<int n> void SuperFX::op_with_r() {
|
||||||
regs.sreg = ®s.r[n];
|
regs.sreg = n;
|
||||||
regs.dreg = ®s.r[n];
|
regs.dreg = n;
|
||||||
regs.sfr.b = 1;
|
regs.sfr.b = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,7 +519,7 @@ template<int n> void SuperFX::op_sms_r() {
|
|||||||
//$b0-bf(b1): moves rN
|
//$b0-bf(b1): moves rN
|
||||||
template<int n> void SuperFX::op_from_r() {
|
template<int n> void SuperFX::op_from_r() {
|
||||||
if(regs.sfr.b == 0) {
|
if(regs.sfr.b == 0) {
|
||||||
regs.sreg = ®s.r[n];
|
regs.sreg = n;
|
||||||
} else {
|
} else {
|
||||||
regs.dr() = regs.r[n];
|
regs.dr() = regs.r[n];
|
||||||
regs.sfr.ov = (regs.dr() & 0x80);
|
regs.sfr.ov = (regs.dr() & 0x80);
|
@@ -1,5 +1,5 @@
|
|||||||
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
|
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
|
||||||
struct reg16_t : noncopyable {
|
struct reg16_t {
|
||||||
uint16 data;
|
uint16 data;
|
||||||
function<void (uint16)> on_modify;
|
function<void (uint16)> on_modify;
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ struct reg16_t : noncopyable {
|
|||||||
inline unsigned operator = (const reg16_t& i) { return assign(i); }
|
inline unsigned operator = (const reg16_t& i) { return assign(i); }
|
||||||
|
|
||||||
reg16_t() : data(0) {}
|
reg16_t() : data(0) {}
|
||||||
|
reg16_t(const reg16_t&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sfr_t {
|
struct sfr_t {
|
||||||
@@ -149,17 +150,17 @@ struct regs_t {
|
|||||||
uint16 ramar; //RAM buffer address register
|
uint16 ramar; //RAM buffer address register
|
||||||
uint8 ramdr; //RAM buffer data register
|
uint8 ramdr; //RAM buffer data register
|
||||||
|
|
||||||
reg16_t *sreg, *dreg;
|
unsigned sreg, dreg;
|
||||||
reg16_t& sr() { return *sreg; } //source register (from)
|
reg16_t& sr() { return r[sreg]; } //source register (from)
|
||||||
reg16_t& dr() { return *dreg; } //destination register (to)
|
reg16_t& dr() { return r[dreg]; } //destination register (to)
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
sfr.b = 0;
|
sfr.b = 0;
|
||||||
sfr.alt1 = 0;
|
sfr.alt1 = 0;
|
||||||
sfr.alt2 = 0;
|
sfr.alt2 = 0;
|
||||||
|
|
||||||
sreg = &r[0];
|
sreg = 0;
|
||||||
dreg = &r[0];
|
dreg = 0;
|
||||||
}
|
}
|
||||||
} regs;
|
} regs;
|
||||||
|
|
@@ -1,3 +1,5 @@
|
|||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
void SuperFX::disassemble_opcode(char *output) {
|
void SuperFX::disassemble_opcode(char *output) {
|
||||||
*output = 0;
|
*output = 0;
|
||||||
|
|
||||||
@@ -273,3 +275,5 @@ void SuperFX::disassemble_alt3(char *output) {
|
|||||||
#undef op0
|
#undef op0
|
||||||
#undef op1
|
#undef op1
|
||||||
#undef op2
|
#undef op2
|
||||||
|
|
||||||
|
#endif
|
@@ -1,3 +1,5 @@
|
|||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
uint8 SuperFX::op_read(uint16 addr) {
|
uint8 SuperFX::op_read(uint16 addr) {
|
||||||
uint16 offset = addr - regs.cbr;
|
uint16 offset = addr - regs.cbr;
|
||||||
if(offset < 512) {
|
if(offset < 512) {
|
||||||
@@ -65,3 +67,5 @@ void SuperFX::memory_reset() {
|
|||||||
pixelcache[n].bitpend = 0x00;
|
pixelcache[n].bitpend = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -1,7 +1,7 @@
|
|||||||
#ifdef SUPERFX_CPP
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
uint8 SuperFX::mmio_read(unsigned addr) {
|
uint8 SuperFX::mmio_read(unsigned addr) {
|
||||||
scheduler.sync_cpucop();
|
cpu.synchronize_coprocessor();
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
if(addr >= 0x3100 && addr <= 0x32ff) {
|
if(addr >= 0x3100 && addr <= 0x32ff) {
|
||||||
@@ -53,7 +53,7 @@ uint8 SuperFX::mmio_read(unsigned addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::mmio_write(unsigned addr, uint8 data) {
|
void SuperFX::mmio_write(unsigned addr, uint8 data) {
|
||||||
scheduler.sync_cpucop();
|
cpu.synchronize_coprocessor();
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
if(addr >= 0x3100 && addr <= 0x32ff) {
|
if(addr >= 0x3100 && addr <= 0x32ff) {
|
96
asnes/chip/superfx/serialization.cpp
Normal file
96
asnes/chip/superfx/serialization.cpp
Normal file
@@ -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
|
@@ -1,8 +1,9 @@
|
|||||||
#include <../base.hpp>
|
#include <snes.hpp>
|
||||||
|
|
||||||
#define SUPERFX_CPP
|
#define SUPERFX_CPP
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
|
|
||||||
|
#include "serialization.cpp"
|
||||||
#include "bus/bus.cpp"
|
#include "bus/bus.cpp"
|
||||||
#include "core/core.cpp"
|
#include "core/core.cpp"
|
||||||
#include "memory/memory.cpp"
|
#include "memory/memory.cpp"
|
||||||
@@ -12,11 +13,18 @@ namespace SNES {
|
|||||||
|
|
||||||
SuperFX superfx;
|
SuperFX superfx;
|
||||||
|
|
||||||
|
void SuperFX::Enter() { superfx.enter(); }
|
||||||
|
|
||||||
void SuperFX::enter() {
|
void SuperFX::enter() {
|
||||||
while(true) {
|
while(true) {
|
||||||
while(regs.sfr.g == 0) {
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.sfr.g == 0) {
|
||||||
add_clocks(6);
|
add_clocks(6);
|
||||||
scheduler.sync_copcpu();
|
synchronize_cpu();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
|
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
|
||||||
@@ -24,19 +32,18 @@ void SuperFX::enter() {
|
|||||||
|
|
||||||
if(++instruction_counter >= 128) {
|
if(++instruction_counter >= 128) {
|
||||||
instruction_counter = 0;
|
instruction_counter = 0;
|
||||||
scheduler.sync_copcpu();
|
synchronize_cpu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::init() {
|
void SuperFX::init() {
|
||||||
initialize_opcode_table();
|
initialize_opcode_table();
|
||||||
regs.r[14].on_modify = bind(&SuperFX::r14_modify, this);
|
regs.r[14].on_modify = { &SuperFX::r14_modify, this };
|
||||||
regs.r[15].on_modify = bind(&SuperFX::r15_modify, this);
|
regs.r[15].on_modify = { &SuperFX::r15_modify, this };
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::enable() {
|
void SuperFX::enable() {
|
||||||
for(unsigned i = 0x3000; i <= 0x32ff; i++) memory::mmio.map(i, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::power() {
|
void SuperFX::power() {
|
||||||
@@ -45,6 +52,7 @@ void SuperFX::power() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::reset() {
|
void SuperFX::reset() {
|
||||||
|
create(SuperFX::Enter, system.cpu_frequency());
|
||||||
superfxbus.init();
|
superfxbus.init();
|
||||||
instruction_counter = 0;
|
instruction_counter = 0;
|
||||||
|
|
||||||
@@ -70,4 +78,4 @@ void SuperFX::reset() {
|
|||||||
timing_reset();
|
timing_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
#include "bus/bus.hpp"
|
#include "bus/bus.hpp"
|
||||||
|
|
||||||
class SuperFX : public MMIO {
|
class SuperFX : public Coprocessor, public MMIO {
|
||||||
public:
|
public:
|
||||||
#include "core/core.hpp"
|
#include "core/core.hpp"
|
||||||
#include "memory/memory.hpp"
|
#include "memory/memory.hpp"
|
||||||
@@ -8,12 +8,13 @@ public:
|
|||||||
#include "timing/timing.hpp"
|
#include "timing/timing.hpp"
|
||||||
#include "disasm/disasm.hpp"
|
#include "disasm/disasm.hpp"
|
||||||
|
|
||||||
|
static void Enter();
|
||||||
void enter();
|
void enter();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void enable();
|
void enable();
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
|
void serialize(serializer&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned clockmode;
|
unsigned clockmode;
|
@@ -1,3 +1,5 @@
|
|||||||
|
#ifdef SUPERFX_CPP
|
||||||
|
|
||||||
void SuperFX::add_clocks(unsigned clocks) {
|
void SuperFX::add_clocks(unsigned clocks) {
|
||||||
if(regs.romcl) {
|
if(regs.romcl) {
|
||||||
regs.romcl -= min(clocks, regs.romcl);
|
regs.romcl -= min(clocks, regs.romcl);
|
||||||
@@ -14,8 +16,8 @@ void SuperFX::add_clocks(unsigned clocks) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.addclocks_cop(clocks);
|
step(clocks);
|
||||||
scheduler.sync_copcpu();
|
synchronize_cpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperFX::rombuffer_sync() {
|
void SuperFX::rombuffer_sync() {
|
||||||
@@ -91,3 +93,5 @@ void SuperFX::timing_reset() {
|
|||||||
regs.ramar = 0;
|
regs.ramar = 0;
|
||||||
regs.ramdr = 0;
|
regs.ramdr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user