diff --git a/bsnes/Makefile b/bsnes/Makefile index aba3d8ea..db90cf82 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,14 +1,15 @@ include nall/Makefile snes := snes +gameboy := gameboy profile := compatibility ui := ui # compiler c := $(compiler) -std=gnu99 cpp := $(subst cc,++,$(compiler)) -std=gnu++0x -flags := -O3 -fomit-frame-pointer -I. -I$(snes) +flags := -O3 -fomit-frame-pointer -I. link := -objects := +objects := libco # profile-guided instrumentation # flags += -fprofile-generate @@ -45,7 +46,10 @@ compile = \ all: build; +obj/libco.o: libco/libco.c libco/* + include $(snes)/Makefile +include $(gameboy)/Makefile include $(ui)/Makefile objects := $(patsubst %,obj/%.o,$(objects)) @@ -90,6 +94,6 @@ clean: ui_clean -@$(call delete,*.manifest) archive-all: - tar -cjf bsnes.tar.bz2 data launcher libco nall obj out phoenix ruby snes ui Makefile cc.bat clean.bat sync.sh + tar -cjf bsnes.tar.bz2 data gameboy launcher libco nall obj out phoenix ruby snes ui Makefile cc.bat clean.bat sync.sh help:; diff --git a/bsnes/gameboy/Makefile b/bsnes/gameboy/Makefile new file mode 100755 index 00000000..149614c4 --- /dev/null +++ b/bsnes/gameboy/Makefile @@ -0,0 +1,11 @@ +gameboy_objects := gameboy-system gameboy-scheduler +gameboy_objects += gameboy-memory gameboy-cartridge +gameboy_objects += gameboy-cpu gameboy-lcd +objects += $(gameboy_objects) + +obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/) +obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/) +obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/) +obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/) +obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/) +obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/) diff --git a/bsnes/gameboy/cartridge/cartridge.cpp b/bsnes/gameboy/cartridge/cartridge.cpp new file mode 100755 index 00000000..7939d68c --- /dev/null +++ b/bsnes/gameboy/cartridge/cartridge.cpp @@ -0,0 +1,168 @@ +#include + +#include + +#define CARTRIDGE_CPP +namespace GameBoy { + +#include "mbc0/mbc0.cpp" +#include "mbc1/mbc1.cpp" +#include "mbc2/mbc2.cpp" +#include "mbc3/mbc3.cpp" +#include "mbc5/mbc5.cpp" +#include "mmm01/mmm01.cpp" +#include "huc1/huc1.cpp" +#include "huc3/huc3.cpp" +Cartridge cartridge; + +void Cartridge::load(uint8_t *data, unsigned size) { +//uint32_t crc = crc32_calculate(data, size); +//print("CRC32 = ", hex<4>(crc), "\n"); + + romdata = new uint8[romsize = size]; + memcpy(romdata, data, size); + + char name[17]; + memcpy(name, romdata + 0x0134, 16); + name[16] = 0; + info.name = name; + info.name.rtrim(); + + info.cgbflag = romdata[0x0143]; + info.sgbflag = romdata[0x0146]; + + info.mapper = Mapper::Unknown; + info.ram = false; + info.battery = false; + info.rtc = false; + + switch(romdata[0x0147]) { + case 0x00: info.mapper = Mapper::MBC0; break; + case 0x01: info.mapper = Mapper::MBC1; break; + case 0x02: info.mapper = Mapper::MBC1; info.ram = true; break; + case 0x03: info.mapper = Mapper::MBC1; info.ram = true; info.battery = true; break; + case 0x05: info.mapper = Mapper::MBC2; info.ram = true; break; + case 0x06: info.mapper = Mapper::MBC2; info.ram = true; info.battery = true; break; + case 0x08: info.mapper = Mapper::MBC0; info.ram = true; break; + case 0x09: info.mapper = Mapper::MBC0; info.ram = true; info.battery = true; break; + case 0x0b: info.mapper = Mapper::MMM01; break; + case 0x0c: info.mapper = Mapper::MMM01; info.ram = true; break; + case 0x0d: info.mapper = Mapper::MMM01; info.ram = true; info.battery = true; break; + case 0x0f: info.mapper = Mapper::MBC3; info.rtc = true; info.battery = true; break; + case 0x10: info.mapper = Mapper::MBC3; info.rtc = true; info.ram = true; info.battery = true; break; + case 0x11: info.mapper = Mapper::MBC3; break; + case 0x12: info.mapper = Mapper::MBC3; info.ram = true; break; + case 0x13: info.mapper = Mapper::MBC3; info.ram = true; info.battery = true; break; + case 0x19: info.mapper = Mapper::MBC5; break; + case 0x1a: info.mapper = Mapper::MBC5; info.ram = true; break; + case 0x1b: info.mapper = Mapper::MBC5; info.ram = true; info.battery = true; break; + case 0x1c: info.mapper = Mapper::MBC5; info.rumble = true; break; + case 0x1d: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; break; + case 0x1e: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; info.battery = true; break; + case 0xfc: break; //Pocket Camera + case 0xfd: break; //Bandai TAMA5 + case 0xfe: info.mapper = Mapper::HuC3; break; + case 0xff: info.mapper = Mapper::HuC1; info.ram = true; info.battery = true; break; + } +//print("Mapper: ", hex<2>(romdata[0x0147]), "\n"); + + switch(romdata[0x0148]) { default: + case 0x00: info.romsize = 2 * 16 * 1024; break; + case 0x01: info.romsize = 4 * 16 * 1024; break; + case 0x02: info.romsize = 8 * 16 * 1024; break; + case 0x03: info.romsize = 16 * 16 * 1024; break; + case 0x04: info.romsize = 32 * 16 * 1024; break; + case 0x05: info.romsize = 64 * 16 * 1024; break; + case 0x06: info.romsize = 128 * 16 * 1024; break; + case 0x07: info.romsize = 256 * 16 * 1024; break; + case 0x52: info.romsize = 72 * 16 * 1024; break; + case 0x53: info.romsize = 80 * 16 * 1024; break; + case 0x54: info.romsize = 96 * 16 * 1024; break; + } + + switch(romdata[0x0149]) { default: + case 0x00: info.ramsize = 0 * 1024; break; + case 0x01: info.ramsize = 2 * 1024; break; + case 0x02: info.ramsize = 8 * 1024; break; + case 0x03: info.ramsize = 32 * 1024; break; + } + + if(info.mapper == Mapper::MBC2) info.ramsize = 512; //512 x 4-bit + + ramdata = new uint8_t[ramsize = info.ramsize](); + + loaded = true; +} + +void Cartridge::unload() { + if(loaded == false) return; + + if(romdata) { delete[] romdata; romdata = 0; } + if(ramdata) { delete[] ramdata; ramdata = 0; } + loaded = false; +} + +uint8 Cartridge::rom_read(unsigned addr) { + if(addr >= romsize) addr %= romsize; + return romdata[addr]; +} + +void Cartridge::rom_write(unsigned addr, uint8 data) { + if(addr >= romsize) addr %= romsize; + romdata[addr] = data; +} + +uint8 Cartridge::ram_read(unsigned addr) { + if(ramsize == 0) return 0x00; + if(addr >= ramsize) addr %= ramsize; + return ramdata[addr]; +} + +void Cartridge::ram_write(unsigned addr, uint8 data) { + if(ramsize == 0) return; + if(addr >= ramsize) addr %= ramsize; + ramdata[addr] = data; +} + +void Cartridge::power() { + mbc0.power(); + mbc1.power(); + mbc2.power(); + mbc3.power(); + mbc5.power(); + mmm01.power(); + huc1.power(); + huc3.power(); + map(); +} + +void Cartridge::map() { + MMIO *mapper = 0; + switch(info.mapper) { default: + case Mapper::MBC0: mapper = &mbc0; break; + case Mapper::MBC1: mapper = &mbc1; break; + case Mapper::MBC2: mapper = &mbc2; break; + case Mapper::MBC3: mapper = &mbc3; break; + case Mapper::MBC5: mapper = &mbc5; break; + case Mapper::MMM01: mapper = &mmm01; break; + case Mapper::HuC1: mapper = &huc1; break; + case Mapper::HuC3: mapper = &huc3; break; + } + + if(mapper) { + for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper; + for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper; + } +} + +Cartridge::Cartridge() { + loaded = false; + romdata = 0; + ramdata = 0; +} + +Cartridge::~Cartridge() { + unload(); +} + +} diff --git a/bsnes/gameboy/cartridge/cartridge.hpp b/bsnes/gameboy/cartridge/cartridge.hpp new file mode 100755 index 00000000..fc0cb15f --- /dev/null +++ b/bsnes/gameboy/cartridge/cartridge.hpp @@ -0,0 +1,61 @@ +struct Cartridge : property { + #include "mbc0/mbc0.hpp" + #include "mbc1/mbc1.hpp" + #include "mbc2/mbc2.hpp" + #include "mbc3/mbc3.hpp" + #include "mbc5/mbc5.hpp" + #include "mmm01/mmm01.hpp" + #include "huc1/huc1.hpp" + #include "huc3/huc3.hpp" + + enum Mapper : unsigned { + MBC0, + MBC1, + MBC2, + MBC3, + MBC5, + MMM01, + HuC1, + HuC3, + Unknown, + }; + + struct Information { + string name; + uint8 cgbflag; + uint8 sgbflag; + + Mapper mapper; + bool ram; + bool battery; + bool rtc; + bool rumble; + + unsigned romsize; + unsigned ramsize; + } info; + + readonly loaded; + + uint8_t *romdata; + unsigned romsize; + + uint8_t *ramdata; + unsigned ramsize; + + void load(uint8_t *data, unsigned size); + void unload(); + + uint8 rom_read(unsigned addr); + void rom_write(unsigned addr, uint8 data); + uint8 ram_read(unsigned addr); + void ram_write(unsigned addr, uint8 data); + + void power(); + void map(); + + Cartridge(); + ~Cartridge(); +}; + +extern Cartridge cartridge; diff --git a/bsnes/gameboy/cartridge/huc1/huc1.cpp b/bsnes/gameboy/cartridge/huc1/huc1.cpp new file mode 100755 index 00000000..8f64b560 --- /dev/null +++ b/bsnes/gameboy/cartridge/huc1/huc1.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC1::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = data; + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC1::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/bsnes/gameboy/cartridge/huc1/huc1.hpp b/bsnes/gameboy/cartridge/huc1/huc1.hpp new file mode 100755 index 00000000..f7bcc37d --- /dev/null +++ b/bsnes/gameboy/cartridge/huc1/huc1.hpp @@ -0,0 +1,9 @@ +struct HuC1 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc1; diff --git a/bsnes/gameboy/cartridge/huc3/huc3.cpp b/bsnes/gameboy/cartridge/huc3/huc3.cpp new file mode 100755 index 00000000..aef74d69 --- /dev/null +++ b/bsnes/gameboy/cartridge/huc3/huc3.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC3::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = data; + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/bsnes/gameboy/cartridge/huc3/huc3.hpp b/bsnes/gameboy/cartridge/huc3/huc3.hpp new file mode 100755 index 00000000..407d3bd4 --- /dev/null +++ b/bsnes/gameboy/cartridge/huc3/huc3.hpp @@ -0,0 +1,9 @@ +struct HuC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc3; diff --git a/bsnes/gameboy/cartridge/mbc0/mbc0.cpp b/bsnes/gameboy/cartridge/mbc0/mbc0.cpp new file mode 100755 index 00000000..46461b77 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc0/mbc0.cpp @@ -0,0 +1,25 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC0::mmio_read(uint16 addr) { + if((addr & 0x8000) == 0x0000) { //0000-7fff + return cartridge.rom_read(addr); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + return cartridge.ram_read(addr & 0x1fff); + } + + return 0x00; +} + +void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0xa000) { //a000-bfff + cartridge.ram_write(addr & 0x1fff, data); + return; + } +} + +void Cartridge::MBC0::power() { +} + +#endif diff --git a/bsnes/gameboy/cartridge/mbc0/mbc0.hpp b/bsnes/gameboy/cartridge/mbc0/mbc0.hpp new file mode 100755 index 00000000..da7390ea --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc0/mbc0.hpp @@ -0,0 +1,5 @@ +struct MBC0 : MMIO { + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc0; diff --git a/bsnes/gameboy/cartridge/mbc1/mbc1.cpp b/bsnes/gameboy/cartridge/mbc1/mbc1.cpp new file mode 100755 index 00000000..50622e82 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc1/mbc1.cpp @@ -0,0 +1,70 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC1::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + if(mode_select == 0) { + return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff)); + } else { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(mode_select == 0) { + return cartridge.ram_read(addr & 0x1fff); + } else { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + } + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = (data & 0x1f) + ((data & 0x1f) == 0); + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data & 0x03; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + mode_select = data & 0x01; + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(mode_select == 0) { + cartridge.ram_write(addr & 0x1fff, data); + } else { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } + } + return; + } +} + +void Cartridge::MBC1::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; + mode_select = 0; +} + +#endif diff --git a/bsnes/gameboy/cartridge/mbc1/mbc1.hpp b/bsnes/gameboy/cartridge/mbc1/mbc1.hpp new file mode 100755 index 00000000..099cf43d --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc1/mbc1.hpp @@ -0,0 +1,10 @@ +struct MBC1 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + bool mode_select; //6000-7fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc1; diff --git a/bsnes/gameboy/cartridge/mbc2/mbc2.cpp b/bsnes/gameboy/cartridge/mbc2/mbc2.cpp new file mode 100755 index 00000000..3b952c78 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc2/mbc2.cpp @@ -0,0 +1,42 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC2::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xfe00) == 0xa000) { //a000-a1ff + if(ram_enable) return cartridge.ram_read(addr & 0x1ff); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe100) == 0x0000) { //0000-1fff [d8=0] + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1] + rom_select = (data & 0x0f) + ((data & 0x0f) == 0); + return; + } + + if((addr & 0xfe00) == 0xa000) { //a000-a1ff + if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f); + return; + } +} + +void Cartridge::MBC2::power() { + ram_enable = false; + rom_select = 0x01; +} + +#endif diff --git a/bsnes/gameboy/cartridge/mbc2/mbc2.hpp b/bsnes/gameboy/cartridge/mbc2/mbc2.hpp new file mode 100755 index 00000000..be9b7db6 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc2/mbc2.hpp @@ -0,0 +1,8 @@ +struct MBC2 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc2; diff --git a/bsnes/gameboy/cartridge/mbc3/mbc3.cpp b/bsnes/gameboy/cartridge/mbc3/mbc3.cpp new file mode 100755 index 00000000..de7701ea --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc3/mbc3.cpp @@ -0,0 +1,120 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::MBC3::second() { + if(rtc_halt == false) { + if(++rtc_second >= 60) { + rtc_second = 0; + if(++rtc_minute >= 60) { + rtc_minute = 0; + if(++rtc_hour >= 24) { + rtc_hour = 0; + if(++rtc_day >= 512) { + rtc_day = 0; + rtc_day_carry = true; + } + } + } + } + } +} + +uint8 Cartridge::MBC3::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + if(ram_select == 0x08) return rtc_latch_second; + if(ram_select == 0x09) return rtc_latch_minute; + if(ram_select == 0x0a) return rtc_latch_hour; + if(ram_select == 0x0b) return rtc_latch_day; + if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8); + } + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = (data & 0x7f) + ((data & 0x7f) == 0); + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + if(rtc_latch == 0 && data == 1) { + rtc_latch_second = rtc_second; + rtc_latch_minute = rtc_minute; + rtc_latch_hour = rtc_hour; + rtc_latch_day = rtc_day; + rtc_latch_day_carry = rtc_day_carry; + } + rtc_latch = data; + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } else if(ram_select == 0x08) { + if(data >= 60) data = 0; + rtc_second = data; + } else if(ram_select == 0x09) { + if(data >= 60) data = 0; + rtc_minute = data; + } else if(ram_select == 0x0a) { + if(data >= 24) data = 0; + rtc_hour = data; + } else if(ram_select == 0x0b) { + rtc_day = (rtc_day & 0x0100) | data; + } else if(ram_select == 0x0c) { + rtc_day = ((data & 1) << 8) | (rtc_day & 0xff); + rtc_halt = data & 0x40; + rtc_day_carry = data & 0x80; + } + } + return; + } +} + +void Cartridge::MBC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; + rtc_latch = 0; + + rtc_halt = true; + rtc_second = 0; + rtc_minute = 0; + rtc_hour = 0; + rtc_day = 0; + rtc_day_carry = false; + + rtc_latch_second = 0; + rtc_latch_minute = 0; + rtc_latch_hour = 0; + rtc_latch_day = 0; + rtc_latch_day_carry = false; +} + +#endif diff --git a/bsnes/gameboy/cartridge/mbc3/mbc3.hpp b/bsnes/gameboy/cartridge/mbc3/mbc3.hpp new file mode 100755 index 00000000..d83ba182 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc3/mbc3.hpp @@ -0,0 +1,24 @@ +struct MBC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + bool rtc_latch; //6000-7fff + + bool rtc_halt; + unsigned rtc_second; + unsigned rtc_minute; + unsigned rtc_hour; + unsigned rtc_day; + bool rtc_day_carry; + + unsigned rtc_latch_second; + unsigned rtc_latch_minute; + unsigned rtc_latch_hour; + unsigned rtc_latch_day; + unsigned rtc_latch_day_carry; + + void second(); + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc3; diff --git a/bsnes/gameboy/cartridge/mbc5/mbc5.cpp b/bsnes/gameboy/cartridge/mbc5/mbc5.cpp new file mode 100755 index 00000000..263e5125 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc5/mbc5.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC5::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xf000) == 0x2000) { //2000-2fff + rom_select = (rom_select & 0x0100) | data; + return; + } + + if((addr & 0xf000) == 0x3000) { //3000-3fff + rom_select = ((data & 1) << 8) | (rom_select & 0x00ff); + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data & 0x0f; + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::MBC5::power() { + ram_enable = false; + rom_select = 0x001; + ram_select = 0x00; +} + +#endif diff --git a/bsnes/gameboy/cartridge/mbc5/mbc5.hpp b/bsnes/gameboy/cartridge/mbc5/mbc5.hpp new file mode 100755 index 00000000..7d5b0a30 --- /dev/null +++ b/bsnes/gameboy/cartridge/mbc5/mbc5.hpp @@ -0,0 +1,9 @@ +struct MBC5 : MMIO { + bool ram_enable; //0000-1fff + uint16 rom_select; //2000-2fff + 3000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc5; diff --git a/bsnes/gameboy/cartridge/mmm01/mmm01.cpp b/bsnes/gameboy/cartridge/mmm01/mmm01.cpp new file mode 100755 index 00000000..7bef9219 --- /dev/null +++ b/bsnes/gameboy/cartridge/mmm01/mmm01.cpp @@ -0,0 +1,65 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MMM01::mmio_read(uint16 addr) { + if((addr & 0x8000) == 0x0000) { + if(rom_mode == 0) return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x0000) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff)); + } + + if((addr & 0xc000) == 0x4000) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + if(rom_mode == 0) { + rom_mode = 1; + } else { + ram_enable = (data & 0x0f) == 0x0a; + } + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + if(rom_mode == 0) { + rom_base = data & 0x3f; + } else { + rom_select = data; + } + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + if(rom_mode == 1) { + ram_select = data; + } + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + //unknown purpose + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data); + } +} + +void Cartridge::MMM01::power() { + rom_mode = 0; + rom_base = 0x00; + + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/bsnes/gameboy/cartridge/mmm01/mmm01.hpp b/bsnes/gameboy/cartridge/mmm01/mmm01.hpp new file mode 100755 index 00000000..3474b062 --- /dev/null +++ b/bsnes/gameboy/cartridge/mmm01/mmm01.hpp @@ -0,0 +1,12 @@ +struct MMM01 : MMIO { + bool rom_mode; + uint8 rom_base; + + bool ram_enable; + uint8 rom_select; + uint8 ram_select; + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mmm01; diff --git a/bsnes/gameboy/cpu/core/core.cpp b/bsnes/gameboy/cpu/core/core.cpp new file mode 100755 index 00000000..e1e226e2 --- /dev/null +++ b/bsnes/gameboy/cpu/core/core.cpp @@ -0,0 +1,674 @@ +#ifdef CPU_CPP + +#include "table.cpp" +#include "disassembler.cpp" + +void CPU::op_xx() { +} + +void CPU::op_cb() { + uint8 opcode = op_read(r[PC]++); + (this->*opcode_table_cb[opcode])(); +} + +//8-bit load commands + +template void CPU::op_ld_r_r() { + r[x] = r[y]; +} + +template void CPU::op_ld_r_n() { + r[x] = op_read(r[PC]++); +} + +template void CPU::op_ld_r_hl() { + r[x] = op_read(r[HL]); +} + +template void CPU::op_ld_hl_r() { + op_write(r[HL], r[x]); +} + +void CPU::op_ld_hl_n() { + op_write(r[HL], op_read(r[PC]++)); +} + +template void CPU::op_ld_a_rr() { + r[A] = op_read(r[x]); +} + +void CPU::op_ld_a_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + r[A] = op_read((hi << 8) | (lo << 0)); +} + +template void CPU::op_ld_rr_a() { + op_write(r[x], r[A]); +} + +void CPU::op_ld_nn_a() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + op_write((hi << 8) | (lo << 0), r[A]); +} + +void CPU::op_ld_a_ffn() { + r[A] = op_read(0xff00 + op_read(r[PC]++)); +} + +void CPU::op_ld_ffn_a() { + op_write(0xff00 + op_read(r[PC]++), r[A]); +} + +void CPU::op_ld_a_ffc() { + r[A] = op_read(0xff00 + r[C]); +} + +void CPU::op_ld_ffc_a() { + op_write(0xff00 + r[C], r[A]); +} + +void CPU::op_ldi_hl_a() { + op_write(r[HL], r[A]); + r[HL]++; +} + +void CPU::op_ldi_a_hl() { + r[A] = op_read(r[HL]); + r[HL]++; +} + +void CPU::op_ldd_hl_a() { + op_write(r[HL], r[A]); + r[HL]--; +} + +void CPU::op_ldd_a_hl() { + r[A] = op_read(r[HL]); + r[HL]--; +} + +//16-bit load commands + +template void CPU::op_ld_rr_nn() { + r[x] = op_read(r[PC]++) << 0; + r[x] |= op_read(r[PC]++) << 8; +} + +void CPU::op_ld_nn_sp() { + uint16 addr = op_read(r[PC]++) << 0; + addr |= op_read(r[PC]++) << 8; + op_write(addr + 0, r[SP] >> 0); + op_write(addr + 1, r[SP] >> 8); +} + +void CPU::op_ld_sp_hl() { + r[SP] = r[HL]; + op_io(); +} + +template void CPU::op_push_rr() { + op_write(--r[SP], r[x] >> 8); + op_write(--r[SP], r[x] >> 0); + op_io(); +} + +template void CPU::op_pop_rr() { + r[x] = op_read(r[SP]++) << 0; + r[x] |= op_read(r[SP]++) << 8; +} + +//8-bit arithmetic commands + +void CPU::opi_add_a(uint8 x) { + uint16 rh = r[A] + x; + uint16 rl = (r[A] & 0x0f) + (x & 0x0f); + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 0; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_add_a_r() { opi_add_a(r[x]); } +void CPU::op_add_a_n() { opi_add_a(op_read(r[PC]++)); } +void CPU::op_add_a_hl() { opi_add_a(op_read(r[HL])); } + +void CPU::opi_adc_a(uint8 x) { + uint16 rh = r[A] + x + r.f.c; + uint16 rl = (r[A] & 0x0f) + (x & 0x0f) + r.f.c; + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 0; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_adc_a_r() { opi_adc_a(r[x]); } +void CPU::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); } +void CPU::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); } + +void CPU::opi_sub_a(uint8 x) { + uint16 rh = r[A] - x; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f); + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_sub_a_r() { opi_sub_a(r[x]); } +void CPU::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); } +void CPU::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); } + +void CPU::opi_sbc_a(uint8 x) { + uint16 rh = r[A] - x - r.f.c; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f) - r.f.c; + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_sbc_a_r() { opi_sbc_a(r[x]); } +void CPU::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); } +void CPU::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); } + +void CPU::opi_and_a(uint8 x) { + r[A] &= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 1; + r.f.c = 0; +} + +template void CPU::op_and_a_r() { opi_and_a(r[x]); } +void CPU::op_and_a_n() { opi_and_a(op_read(r[PC]++)); } +void CPU::op_and_a_hl() { opi_and_a(op_read(r[HL])); } + +void CPU::opi_xor_a(uint8 x) { + r[A] ^= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_xor_a_r() { opi_xor_a(r[x]); } +void CPU::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); } +void CPU::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); } + +void CPU::opi_or_a(uint8 x) { + r[A] |= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_or_a_r() { opi_or_a(r[x]); } +void CPU::op_or_a_n() { opi_or_a(op_read(r[PC]++)); } +void CPU::op_or_a_hl() { opi_or_a(op_read(r[HL])); } + +void CPU::opi_cp_a(uint8 x) { + uint16 rh = r[A] - x; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f); + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_cp_a_r() { opi_cp_a(r[x]); } +void CPU::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); } +void CPU::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); } + +template void CPU::op_inc_r() { + r[x]++; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = (r[x] & 0x0f) == 0x00; +} + +void CPU::op_inc_hl() { + uint8 n = op_read(r[HL]); + op_write(r[HL], ++n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = (n & 0x0f) == 0x00; +} + +template void CPU::op_dec_r() { + r[x]--; + r.f.z = r[x] == 0; + r.f.n = 1; + r.f.h = (r[x] & 0x0f) == 0x0f; +} + +void CPU::op_dec_hl() { + uint8 n = op_read(r[HL]); + op_write(r[HL], --n); + r.f.z = n == 0; + r.f.n = 1; + r.f.h = (n & 0x0f) == 0x0f; +} + +void CPU::op_daa() { + uint16 a = r[A]; + if(r.f.n == 0) { + if(r.f.h || (a & 0x0f) > 0x09) a += 0x06; + if(r.f.c || (a ) > 0x9f) a += 0x60; + } else { + if(r.f.h) { + a -= 0x06; + if(r.f.c == 0) a &= 0xff; + } + if(r.f.c) a -= 0x60; + } + r[A] = a; + r.f.z = r[A] == 0; + r.f.h = 0; + r.f.c |= a & 0x100; +} + +void CPU::op_cpl() { + r[A] ^= 0xff; + r.f.n = 1; + r.f.h = 1; +} + +//16-bit arithmetic commands + +template void CPU::op_add_hl_rr() { + op_io(); + uint32 rb = (r[HL] + r[x]); + uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff); + r[HL] = rb; + r.f.n = 0; + r.f.h = rn > 0x0fff; + r.f.c = rb > 0xffff; +} + +template void CPU::op_inc_rr() { + op_io(); + r[x]++; +} + +template void CPU::op_dec_rr() { + op_io(); + r[x]--; +} + +void CPU::op_add_sp_n() { + op_io(); + op_io(); + signed n = (int8)op_read(r[PC]++); + r.f.z = 0; + r.f.n = 0; + r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; + r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; + r[SP] += n; +} + +void CPU::op_ld_hl_sp_n() { + op_io(); + signed n = (int8)op_read(r[PC]++); + r.f.z = 0; + r.f.n = 0; + r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; + r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; + r[HL] = r[SP] + n; +} + +//rotate/shift commands + +void CPU::op_rlca() { + r[A] = (r[A] << 1) | (r[A] >> 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[A] & 0x01; +} + +void CPU::op_rla() { + bool c = r[A] & 0x80; + r[A] = (r[A] << 1) | (r.f.c << 0); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rrca() { + r[A] = (r[A] >> 1) | (r[A] << 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[A] & 0x80; +} + +void CPU::op_rra() { + bool c = r[A] & 0x01; + r[A] = (r[A] >> 1) | (r.f.c << 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_rlc_r() { + r[x] = (r[x] << 1) | (r[x] >> 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[x] & 0x01; +} + +void CPU::op_rlc_hl() { + uint8 n = op_read(r[HL]); + n = (n << 1) | (n >> 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = n & 0x01; +} + +template void CPU::op_rl_r() { + bool c = r[x] & 0x80; + r[x] = (r[x] << 1) | (r.f.c << 0); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rl_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x80; + n = (n << 1) | (r.f.c << 0); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_rrc_r() { + r[x] = (r[x] >> 1) | (r[x] << 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[x] & 0x80; +} + +void CPU::op_rrc_hl() { + uint8 n = op_read(r[HL]); + n = (n >> 1) | (n << 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = n & 0x80; +} + +template void CPU::op_rr_r() { + bool c = r[x] & 0x01; + r[x] = (r[x] >> 1) | (r.f.c << 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rr_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n = (n >> 1) | (r.f.c << 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_sla_r() { + bool c = r[x] & 0x80; + r[x] <<= 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_sla_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x80; + n <<= 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_swap_r() { + r[x] = (r[x] << 4) | (r[x] >> 4); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +void CPU::op_swap_hl() { + uint8 n = op_read(r[HL]); + n = (n << 4) | (n >> 4); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_sra_r() { + bool c = r[x] & 0x01; + r[x] = (int8)r[x] >> 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_sra_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n = (int8)n >> 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_srl_r() { + bool c = r[x] & 0x01; + r[x] >>= 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_srl_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n >>= 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +//single-bit commands + +template void CPU::op_bit_n_r() { + r.f.z = (r[x] & (1 << b)) == 0; + r.f.n = 0; + r.f.h = 1; +} + +template void CPU::op_bit_n_hl() { + uint8 n = op_read(r[HL]); + r.f.z = (n & (1 << b)) == 0; + r.f.n = 0; + r.f.h = 1; +} + +template void CPU::op_set_n_r() { + r[x] |= 1 << b; +} + +template void CPU::op_set_n_hl() { + uint8 n = op_read(r[HL]); + n |= 1 << b; + op_write(r[HL], n); +} + +template void CPU::op_res_n_r() { + r[x] &= ~(1 << b); +} + +template void CPU::op_res_n_hl() { + uint8 n = op_read(r[HL]); + n &= ~(1 << b); + op_write(r[HL], n); +} + +//control commands + +void CPU::op_ccf() { + r.f.n = 0; + r.f.h = 0; + r.f.c = !r.f.c; +} + +void CPU::op_scf() { + r.f.n = 0; + r.f.h = 0; + r.f.c = 1; +} + +void CPU::op_nop() { +} + +void CPU::op_halt() { + status.halt = true; + while(status.halt == true) op_io(); +} + +void CPU::op_stop() { + status.stop = true; + while(status.stop == true) op_io(); +} + +void CPU::op_di() { + status.ime = 0; +} + +void CPU::op_ei() { + status.ime = 1; +} + +//jump commands + +void CPU::op_jp_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +void CPU::op_jp_hl() { + r[PC] = r[HL]; +} + +template void CPU::op_jp_f_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + if(r.f[x] == y) { + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_jr_n() { + int8 n = op_read(r[PC]++); + r[PC] += n; + op_io(); +} + +template void CPU::op_jr_f_n() { + int8 n = op_read(r[PC]++); + if(r.f[x] == y) { + r[PC] += n; + op_io(); + } +} + +void CPU::op_call_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +template void CPU::op_call_f_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + if(r.f[x] == y) { + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_ret() { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +template void CPU::op_ret_f() { + op_io(); + if(r.f[x] == y) { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_reti() { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + status.ime = 1; +} + +template void CPU::op_rst_n() { + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = n; + op_io(); +} + +#endif diff --git a/bsnes/gameboy/cpu/core/core.hpp b/bsnes/gameboy/cpu/core/core.hpp new file mode 100755 index 00000000..85ebeb1d --- /dev/null +++ b/bsnes/gameboy/cpu/core/core.hpp @@ -0,0 +1,145 @@ +#include "registers.hpp" +void (CPU::*opcode_table[256])(); +void (CPU::*opcode_table_cb[256])(); +void initialize_opcode_table(); + +void op_xx(); +void op_cb(); + +//8-bit load commands +template void op_ld_r_r(); +template void op_ld_r_n(); +template void op_ld_r_hl(); +template void op_ld_hl_r(); +void op_ld_hl_n(); +template void op_ld_a_rr(); +void op_ld_a_nn(); +template void op_ld_rr_a(); +void op_ld_nn_a(); +void op_ld_a_ffn(); +void op_ld_ffn_a(); +void op_ld_a_ffc(); +void op_ld_ffc_a(); +void op_ldi_hl_a(); +void op_ldi_a_hl(); +void op_ldd_hl_a(); +void op_ldd_a_hl(); + +//16-bit load commands +template void op_ld_rr_nn(); +void op_ld_nn_sp(); +void op_ld_sp_hl(); +template void op_push_rr(); +template void op_pop_rr(); + +//8-bit arithmetic commands +void opi_add_a(uint8 x); +template void op_add_a_r(); +void op_add_a_n(); +void op_add_a_hl(); + +void opi_adc_a(uint8 x); +template void op_adc_a_r(); +void op_adc_a_n(); +void op_adc_a_hl(); + +void opi_sub_a(uint8 x); +template void op_sub_a_r(); +void op_sub_a_n(); +void op_sub_a_hl(); + +void opi_sbc_a(uint8 x); +template void op_sbc_a_r(); +void op_sbc_a_n(); +void op_sbc_a_hl(); + +void opi_and_a(uint8 x); +template void op_and_a_r(); +void op_and_a_n(); +void op_and_a_hl(); + +void opi_xor_a(uint8 x); +template void op_xor_a_r(); +void op_xor_a_n(); +void op_xor_a_hl(); + +void opi_or_a(uint8 x); +template void op_or_a_r(); +void op_or_a_n(); +void op_or_a_hl(); + +void opi_cp_a(uint8 x); +template void op_cp_a_r(); +void op_cp_a_n(); +void op_cp_a_hl(); + +template void op_inc_r(); +void op_inc_hl(); +template void op_dec_r(); +void op_dec_hl(); +void op_daa(); +void op_cpl(); + +//16-bit arithmetic commands +template void op_add_hl_rr(); +template void op_inc_rr(); +template void op_dec_rr(); +void op_add_sp_n(); +void op_ld_hl_sp_n(); + +//rotate/shift commands +void op_rlca(); +void op_rla(); +void op_rrca(); +void op_rra(); +template void op_rlc_r(); +void op_rlc_hl(); +template void op_rl_r(); +void op_rl_hl(); +template void op_rrc_r(); +void op_rrc_hl(); +template void op_rr_r(); +void op_rr_hl(); +template void op_sla_r(); +void op_sla_hl(); +template void op_swap_r(); +void op_swap_hl(); +template void op_sra_r(); +void op_sra_hl(); +template void op_srl_r(); +void op_srl_hl(); + +//single-bit commands +template void op_bit_n_r(); +template void op_bit_n_hl(); +template void op_set_n_r(); +template void op_set_n_hl(); +template void op_res_n_r(); +template void op_res_n_hl(); + +//control commands +void op_ccf(); +void op_scf(); +void op_nop(); +void op_halt(); +void op_stop(); +void op_di(); +void op_ei(); + +//jump commands +void op_jp_nn(); +void op_jp_hl(); +template void op_jp_f_nn(); +void op_jr_n(); +template void op_jr_f_n(); +void op_call_nn(); +template void op_call_f_nn(); +void op_ret(); +template void op_ret_f(); +void op_reti(); +template void op_rst_n(); + +//disassembler.cpp +string disassemble(uint16 pc); +string disassemble_opcode(uint16 pc); +string disassemble_opcode_cb(uint16 pc); diff --git a/bsnes/gameboy/cpu/core/disassembler.cpp b/bsnes/gameboy/cpu/core/disassembler.cpp new file mode 100755 index 00000000..dbcee7ee --- /dev/null +++ b/bsnes/gameboy/cpu/core/disassembler.cpp @@ -0,0 +1,560 @@ +#ifdef CPU_CPP + +string CPU::disassemble(uint16 pc) { + char output[80]; + memset(output, ' ', sizeof output); + output[79] = 0; + + string opcode = disassemble_opcode(pc); + string registers = { + " AF:", hex<4>(r[AF]), + " BC:", hex<4>(r[BC]), + " DE:", hex<4>(r[DE]), + " HL:", hex<4>(r[HL]), + " SP:", hex<4>(r[SP]) + }; + + memcpy(output + 0, hex<4>(pc), 4); + memcpy(output + 6, opcode, opcode.length()); + memcpy(output + 23, registers, registers.length()); + output[63] = 0; + return output; +} + +string CPU::disassemble_opcode(uint16 pc) { + uint8 opcode = bus.read(pc); + uint8 p0 = bus.read(pc + 1); + uint8 p1 = bus.read(pc + 2); + uint8 p2 = bus.read(pc + 3); + + switch(opcode) { + case 0x00: return { "nop" }; + case 0x01: return { "ld bc,$", hex<2>(p1), hex<2>(p0) }; + case 0x02: return { "ld (bc),a" }; + case 0x03: return { "inc bc" }; + case 0x04: return { "inc b" }; + case 0x05: return { "dec b" }; + case 0x06: return { "ld b,$", hex<2>(p0) }; + case 0x07: return { "rlc a" }; + case 0x08: return { "ld ($", hex<2>(p1), hex<2>(p0), "),sp" }; + case 0x09: return { "add hl,bc" }; + case 0x0a: return { "ld a,(bc)" }; + case 0x0b: return { "dec bc" }; + case 0x0c: return { "inc c" }; + case 0x0d: return { "dec c" }; + case 0x0e: return { "ld c,$", hex<2>(p0) }; + case 0x0f: return { "rrc a" }; + case 0x10: return { "stop" }; + case 0x11: return { "ld de,$", hex<2>(p1), hex<2>(p0) }; + case 0x12: return { "ld (de),a" }; + case 0x13: return { "inc de" }; + case 0x14: return { "inc d" }; + case 0x15: return { "dec d" }; + case 0x16: return { "ld d,$", hex<2>(p0) }; + case 0x17: return { "rl a" }; + case 0x18: return { "jr $", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x19: return { "add hl,de" }; + case 0x1a: return { "ld a,(de)" }; + case 0x1b: return { "dec de" }; + case 0x1c: return { "inc e" }; + case 0x1d: return { "dec e" }; + case 0x1e: return { "ld e,$", hex<2>(p0) }; + case 0x1f: return { "rr a" }; + case 0x20: return { "jr nz,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x21: return { "ld hl,$", hex<2>(p1), hex<2>(p0) }; + case 0x22: return { "ldi (hl),a" }; + case 0x23: return { "inc hl" }; + case 0x24: return { "inc h" }; + case 0x25: return { "dec h" }; + case 0x26: return { "ld h,$", hex<2>(p0) }; + case 0x27: return { "daa" }; + case 0x28: return { "jr z,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x29: return { "add hl,hl" }; + case 0x2a: return { "ldi a,(hl)" }; + case 0x2b: return { "dec hl" }; + case 0x2c: return { "inc l" }; + case 0x2d: return { "dec l" }; + case 0x2e: return { "ld l,$", hex<2>(p0) }; + case 0x2f: return { "cpl" }; + case 0x30: return { "jr nc,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x31: return { "ld sp,$", hex<2>(p1), hex<2>(p0) }; + case 0x32: return { "ldd (hl),a" }; + case 0x33: return { "inc sp" }; + case 0x34: return { "inc (hl)" }; + case 0x35: return { "dec (hl)" }; + case 0x36: return { "ld (hl),$", hex<2>(p0) }; + case 0x37: return { "scf" }; + case 0x38: return { "jr c,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x39: return { "add hl,sp" }; + case 0x3a: return { "ldd a,(hl)" }; + case 0x3b: return { "dec sp" }; + case 0x3c: return { "inc a" }; + case 0x3d: return { "dec a" }; + case 0x3e: return { "ld a,$", hex<2>(p0) }; + case 0x3f: return { "ccf" }; + case 0x40: return { "ld b,b" }; + case 0x41: return { "ld b,c" }; + case 0x42: return { "ld b,d" }; + case 0x43: return { "ld b,e" }; + case 0x44: return { "ld b,h" }; + case 0x45: return { "ld b,l" }; + case 0x46: return { "ld b,(hl)" }; + case 0x47: return { "ld b,a" }; + case 0x48: return { "ld c,b" }; + case 0x49: return { "ld c,c" }; + case 0x4a: return { "ld c,d" }; + case 0x4b: return { "ld c,e" }; + case 0x4c: return { "ld c,h" }; + case 0x4d: return { "ld c,l" }; + case 0x4e: return { "ld c,(hl)" }; + case 0x4f: return { "ld c,a" }; + case 0x50: return { "ld d,b" }; + case 0x51: return { "ld d,c" }; + case 0x52: return { "ld d,d" }; + case 0x53: return { "ld d,e" }; + case 0x54: return { "ld d,h" }; + case 0x55: return { "ld d,l" }; + case 0x56: return { "ld d,(hl)" }; + case 0x57: return { "ld d,a" }; + case 0x58: return { "ld e,b" }; + case 0x59: return { "ld e,c" }; + case 0x5a: return { "ld e,d" }; + case 0x5b: return { "ld e,e" }; + case 0x5c: return { "ld e,h" }; + case 0x5d: return { "ld e,l" }; + case 0x5e: return { "ld e,(hl)" }; + case 0x5f: return { "ld e,a" }; + case 0x60: return { "ld h,b" }; + case 0x61: return { "ld h,c" }; + case 0x62: return { "ld h,d" }; + case 0x63: return { "ld h,e" }; + case 0x64: return { "ld h,h" }; + case 0x65: return { "ld h,l" }; + case 0x66: return { "ld h,(hl)" }; + case 0x67: return { "ld h,a" }; + case 0x68: return { "ld l,b" }; + case 0x69: return { "ld l,c" }; + case 0x6a: return { "ld l,d" }; + case 0x6b: return { "ld l,e" }; + case 0x6c: return { "ld l,h" }; + case 0x6d: return { "ld l,l" }; + case 0x6e: return { "ld l,(hl)" }; + case 0x6f: return { "ld l,a" }; + case 0x70: return { "ld (hl),b" }; + case 0x71: return { "ld (hl),c" }; + case 0x72: return { "ld (hl),d" }; + case 0x73: return { "ld (hl),e" }; + case 0x74: return { "ld (hl),h" }; + case 0x75: return { "ld (hl),l" }; + case 0x76: return { "halt" }; + case 0x77: return { "ld (hl),a" }; + case 0x78: return { "ld a,b" }; + case 0x79: return { "ld a,c" }; + case 0x7a: return { "ld a,d" }; + case 0x7b: return { "ld a,e" }; + case 0x7c: return { "ld a,h" }; + case 0x7d: return { "ld a,l" }; + case 0x7e: return { "ld a,(hl)" }; + case 0x7f: return { "ld a,a" }; + case 0x80: return { "add a,b" }; + case 0x81: return { "add a,c" }; + case 0x82: return { "add a,d" }; + case 0x83: return { "add a,e" }; + case 0x84: return { "add a,h" }; + case 0x85: return { "add a,l" }; + case 0x86: return { "add a,(hl)" }; + case 0x87: return { "add a,a" }; + case 0x88: return { "adc a,b" }; + case 0x89: return { "adc a,c" }; + case 0x8a: return { "adc a,d" }; + case 0x8b: return { "adc a,e" }; + case 0x8c: return { "adc a,h" }; + case 0x8d: return { "adc a,l" }; + case 0x8e: return { "adc a,(hl)" }; + case 0x8f: return { "adc a,a" }; + case 0x90: return { "sub a,b" }; + case 0x91: return { "sub a,c" }; + case 0x92: return { "sub a,d" }; + case 0x93: return { "sub a,e" }; + case 0x94: return { "sub a,h" }; + case 0x95: return { "sub a,l" }; + case 0x96: return { "sub a,(hl)" }; + case 0x97: return { "sub a,a" }; + case 0x98: return { "sbc a,b" }; + case 0x99: return { "sbc a,c" }; + case 0x9a: return { "sbc a,d" }; + case 0x9b: return { "sbc a,e" }; + case 0x9c: return { "sbc a,h" }; + case 0x9d: return { "sbc a,l" }; + case 0x9e: return { "sbc a,(hl)" }; + case 0x9f: return { "sbc a,a" }; + case 0xa0: return { "and a,b" }; + case 0xa1: return { "and a,c" }; + case 0xa2: return { "and a,d" }; + case 0xa3: return { "and a,e" }; + case 0xa4: return { "and a,h" }; + case 0xa5: return { "and a,l" }; + case 0xa6: return { "and a,(hl)" }; + case 0xa7: return { "and a,a" }; + case 0xa8: return { "xor a,b" }; + case 0xa9: return { "xor a,c" }; + case 0xaa: return { "xor a,d" }; + case 0xab: return { "xor a,e" }; + case 0xac: return { "xor a,h" }; + case 0xad: return { "xor a,l" }; + case 0xae: return { "xor a,(hl)" }; + case 0xaf: return { "xor a,a" }; + case 0xb0: return { "or a,b" }; + case 0xb1: return { "or a,c" }; + case 0xb2: return { "or a,d" }; + case 0xb3: return { "or a,e" }; + case 0xb4: return { "or a,h" }; + case 0xb5: return { "or a,l" }; + case 0xb6: return { "or a,(hl)" }; + case 0xb7: return { "or a,a" }; + case 0xb8: return { "cp a,b" }; + case 0xb9: return { "cp a,c" }; + case 0xba: return { "cp a,d" }; + case 0xbb: return { "cp a,e" }; + case 0xbc: return { "cp a,h" }; + case 0xbd: return { "cp a,l" }; + case 0xbe: return { "cp a,(hl)" }; + case 0xbf: return { "cp a,a" }; + case 0xc0: return { "ret nz" }; + case 0xc1: return { "pop bc" }; + case 0xc2: return { "jp nz,$", hex<2>(p1), hex<2>(p0) }; + case 0xc3: return { "jp $", hex<2>(p1), hex<2>(p0) }; + case 0xc4: return { "call nz,$", hex<2>(p1), hex<2>(p0) }; + case 0xc5: return { "push bc" }; + case 0xc6: return { "add a,$", hex<2>(p0) }; + case 0xc7: return { "rst $0000" }; + case 0xc8: return { "ret z" }; + case 0xc9: return { "ret" }; + case 0xca: return { "jp z,$", hex<2>(p1), hex<2>(p0) }; + case 0xcb: return disassemble_opcode_cb(pc + 1); + case 0xcc: return { "call z,$", hex<2>(p1), hex<2>(p0) }; + case 0xcd: return { "call $", hex<2>(p1), hex<2>(p0) }; + case 0xce: return { "adc a,$", hex<2>(p0) }; + case 0xcf: return { "rst $0008" }; + case 0xd0: return { "ret nc" }; + case 0xd1: return { "pop de" }; + case 0xd2: return { "jp nc,$", hex<2>(p1), hex<2>(p0) }; + case 0xd3: return { "xx" }; + case 0xd4: return { "call nc,$", hex<2>(p1), hex<2>(p0) }; + case 0xd5: return { "push de" }; + case 0xd6: return { "sub a,$", hex<2>(p0) }; + case 0xd7: return { "rst $0010" }; + case 0xd8: return { "ret c" }; + case 0xd9: return { "reti" }; + case 0xda: return { "jp c,$", hex<2>(p1), hex<2>(p0) }; + case 0xdb: return { "xx" }; + case 0xdc: return { "call c,$", hex<2>(p1), hex<2>(p0) }; + case 0xdd: return { "xx" }; + case 0xde: return { "sbc a,$", hex<2>(p0) }; + case 0xdf: return { "rst $0018" }; + case 0xe0: return { "ld ($ff", hex<2>(p0), "),a" }; + case 0xe1: return { "pop hl" }; + case 0xe2: return { "ld ($ff00+c),a" }; + case 0xe3: return { "xx" }; + case 0xe4: return { "xx" }; + case 0xe5: return { "push hl" }; + case 0xe6: return { "and a,$", hex<2>(p0) }; + case 0xe7: return { "rst $0020" }; + case 0xe8: return { "add sp,$", hex<4>((int8)p0) }; + case 0xe9: return { "jp hl" }; + case 0xea: return { "ld ($", hex<2>(p1), hex<2>(p0), "),a" }; + case 0xeb: return { "xx" }; + case 0xec: return { "xx" }; + case 0xed: return { "xx" }; + case 0xee: return { "xor a,$", hex<2>(p0) }; + case 0xef: return { "rst $0028" }; + case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" }; + case 0xf1: return { "pop af" }; + case 0xf2: return { "ld a,($ff00+c)" }; + case 0xf3: return { "di" }; + case 0xf4: return { "xx" }; + case 0xf5: return { "push af" }; + case 0xf6: return { "or a,$", hex<2>(p0) }; + case 0xf7: return { "rst $0030" }; + case 0xf8: return { "ld hl,sp+$", hex<4>((int8)p0) }; + case 0xf9: return { "ld sp,hl" }; + case 0xfa: return { "ld a,($", hex<2>(p1), hex<2>(p0), ")" }; + case 0xfb: return { "ei" }; + case 0xfc: return { "xx" }; + case 0xfd: return { "xx" }; + case 0xfe: return { "cp a,$", hex<2>(p0) }; + case 0xff: return { "rst $0038" }; + } + + return ""; +} + +string CPU::disassemble_opcode_cb(uint16 pc) { + uint8 opcode = bus.read(pc); + uint8 p0 = bus.read(pc + 1); + uint8 p1 = bus.read(pc + 2); + uint8 p2 = bus.read(pc + 3); + + switch(opcode) { + case 0x00: return { "rlc b" }; + case 0x01: return { "rlc c" }; + case 0x02: return { "rlc d" }; + case 0x03: return { "rlc e" }; + case 0x04: return { "rlc h" }; + case 0x05: return { "rlc l" }; + case 0x06: return { "rlc (hl)" }; + case 0x07: return { "rlc a" }; + case 0x08: return { "rrc b" }; + case 0x09: return { "rrc c" }; + case 0x0a: return { "rrc d" }; + case 0x0b: return { "rrc e" }; + case 0x0c: return { "rrc h" }; + case 0x0d: return { "rrc l" }; + case 0x0e: return { "rrc (hl)" }; + case 0x0f: return { "rrc a" }; + case 0x10: return { "rl b" }; + case 0x11: return { "rl c" }; + case 0x12: return { "rl d" }; + case 0x13: return { "rl e" }; + case 0x14: return { "rl h" }; + case 0x15: return { "rl l" }; + case 0x16: return { "rl (hl)" }; + case 0x17: return { "rl a" }; + case 0x18: return { "rr b" }; + case 0x19: return { "rr c" }; + case 0x1a: return { "rr d" }; + case 0x1b: return { "rr e" }; + case 0x1c: return { "rr h" }; + case 0x1d: return { "rr l" }; + case 0x1e: return { "rr (hl)" }; + case 0x1f: return { "rr a" }; + case 0x20: return { "sla b" }; + case 0x21: return { "sla c" }; + case 0x22: return { "sla d" }; + case 0x23: return { "sla e" }; + case 0x24: return { "sla h" }; + case 0x25: return { "sla l" }; + case 0x26: return { "sla (hl)" }; + case 0x27: return { "sla a" }; + case 0x28: return { "sra b" }; + case 0x29: return { "sra c" }; + case 0x2a: return { "sra d" }; + case 0x2b: return { "sra e" }; + case 0x2c: return { "sra h" }; + case 0x2d: return { "sra l" }; + case 0x2e: return { "sra (hl)" }; + case 0x2f: return { "sra a" }; + case 0x30: return { "swap b" }; + case 0x31: return { "swap c" }; + case 0x32: return { "swap d" }; + case 0x33: return { "swap e" }; + case 0x34: return { "swap h" }; + case 0x35: return { "swap l" }; + case 0x36: return { "swap (hl)" }; + case 0x37: return { "swap a" }; + case 0x38: return { "srl b" }; + case 0x39: return { "srl c" }; + case 0x3a: return { "srl d" }; + case 0x3b: return { "srl e" }; + case 0x3c: return { "srl h" }; + case 0x3d: return { "srl l" }; + case 0x3e: return { "srl (hl)" }; + case 0x3f: return { "srl a" }; + case 0x40: return { "bit 0,b" }; + case 0x41: return { "bit 0,c" }; + case 0x42: return { "bit 0,d" }; + case 0x43: return { "bit 0,e" }; + case 0x44: return { "bit 0,h" }; + case 0x45: return { "bit 0,l" }; + case 0x46: return { "bit 0,(hl)" }; + case 0x47: return { "bit 0,a" }; + case 0x48: return { "bit 1,b" }; + case 0x49: return { "bit 1,c" }; + case 0x4a: return { "bit 1,d" }; + case 0x4b: return { "bit 1,e" }; + case 0x4c: return { "bit 1,h" }; + case 0x4d: return { "bit 1,l" }; + case 0x4e: return { "bit 1,(hl)" }; + case 0x4f: return { "bit 1,a" }; + case 0x50: return { "bit 2,b" }; + case 0x51: return { "bit 2,c" }; + case 0x52: return { "bit 2,d" }; + case 0x53: return { "bit 2,e" }; + case 0x54: return { "bit 2,h" }; + case 0x55: return { "bit 2,l" }; + case 0x56: return { "bit 2,(hl)" }; + case 0x57: return { "bit 2,a" }; + case 0x58: return { "bit 3,b" }; + case 0x59: return { "bit 3,c" }; + case 0x5a: return { "bit 3,d" }; + case 0x5b: return { "bit 3,e" }; + case 0x5c: return { "bit 3,h" }; + case 0x5d: return { "bit 3,l" }; + case 0x5e: return { "bit 3,(hl)" }; + case 0x5f: return { "bit 3,a" }; + case 0x60: return { "bit 4,b" }; + case 0x61: return { "bit 4,c" }; + case 0x62: return { "bit 4,d" }; + case 0x63: return { "bit 4,e" }; + case 0x64: return { "bit 4,h" }; + case 0x65: return { "bit 4,l" }; + case 0x66: return { "bit 4,(hl)" }; + case 0x67: return { "bit 4,a" }; + case 0x68: return { "bit 5,b" }; + case 0x69: return { "bit 5,c" }; + case 0x6a: return { "bit 5,d" }; + case 0x6b: return { "bit 5,e" }; + case 0x6c: return { "bit 5,h" }; + case 0x6d: return { "bit 5,l" }; + case 0x6e: return { "bit 5,(hl)" }; + case 0x6f: return { "bit 5,a" }; + case 0x70: return { "bit 6,b" }; + case 0x71: return { "bit 6,c" }; + case 0x72: return { "bit 6,d" }; + case 0x73: return { "bit 6,e" }; + case 0x74: return { "bit 6,h" }; + case 0x75: return { "bit 6,l" }; + case 0x76: return { "bit 6,(hl)" }; + case 0x77: return { "bit 6,a" }; + case 0x78: return { "bit 7,b" }; + case 0x79: return { "bit 7,c" }; + case 0x7a: return { "bit 7,d" }; + case 0x7b: return { "bit 7,e" }; + case 0x7c: return { "bit 7,h" }; + case 0x7d: return { "bit 7,l" }; + case 0x7e: return { "bit 7,(hl)" }; + case 0x7f: return { "bit 7,a" }; + case 0x80: return { "res 0,b" }; + case 0x81: return { "res 0,c" }; + case 0x82: return { "res 0,d" }; + case 0x83: return { "res 0,e" }; + case 0x84: return { "res 0,h" }; + case 0x85: return { "res 0,l" }; + case 0x86: return { "res 0,(hl)" }; + case 0x87: return { "res 0,a" }; + case 0x88: return { "res 1,b" }; + case 0x89: return { "res 1,c" }; + case 0x8a: return { "res 1,d" }; + case 0x8b: return { "res 1,e" }; + case 0x8c: return { "res 1,h" }; + case 0x8d: return { "res 1,l" }; + case 0x8e: return { "res 1,(hl)" }; + case 0x8f: return { "res 1,a" }; + case 0x90: return { "res 2,b" }; + case 0x91: return { "res 2,c" }; + case 0x92: return { "res 2,d" }; + case 0x93: return { "res 2,e" }; + case 0x94: return { "res 2,h" }; + case 0x95: return { "res 2,l" }; + case 0x96: return { "res 2,(hl)" }; + case 0x97: return { "res 2,a" }; + case 0x98: return { "res 3,b" }; + case 0x99: return { "res 3,c" }; + case 0x9a: return { "res 3,d" }; + case 0x9b: return { "res 3,e" }; + case 0x9c: return { "res 3,h" }; + case 0x9d: return { "res 3,l" }; + case 0x9e: return { "res 3,(hl)" }; + case 0x9f: return { "res 3,a" }; + case 0xa0: return { "res 4,b" }; + case 0xa1: return { "res 4,c" }; + case 0xa2: return { "res 4,d" }; + case 0xa3: return { "res 4,e" }; + case 0xa4: return { "res 4,h" }; + case 0xa5: return { "res 4,l" }; + case 0xa6: return { "res 4,(hl)" }; + case 0xa7: return { "res 4,a" }; + case 0xa8: return { "res 5,b" }; + case 0xa9: return { "res 5,c" }; + case 0xaa: return { "res 5,d" }; + case 0xab: return { "res 5,e" }; + case 0xac: return { "res 5,h" }; + case 0xad: return { "res 5,l" }; + case 0xae: return { "res 5,(hl)" }; + case 0xaf: return { "res 5,a" }; + case 0xb0: return { "res 6,b" }; + case 0xb1: return { "res 6,c" }; + case 0xb2: return { "res 6,d" }; + case 0xb3: return { "res 6,e" }; + case 0xb4: return { "res 6,h" }; + case 0xb5: return { "res 6,l" }; + case 0xb6: return { "res 6,(hl)" }; + case 0xb7: return { "res 6,a" }; + case 0xb8: return { "res 7,b" }; + case 0xb9: return { "res 7,c" }; + case 0xba: return { "res 7,d" }; + case 0xbb: return { "res 7,e" }; + case 0xbc: return { "res 7,h" }; + case 0xbd: return { "res 7,l" }; + case 0xbe: return { "res 7,(hl)" }; + case 0xbf: return { "res 7,a" }; + case 0xc0: return { "set 0,b" }; + case 0xc1: return { "set 0,c" }; + case 0xc2: return { "set 0,d" }; + case 0xc3: return { "set 0,e" }; + case 0xc4: return { "set 0,h" }; + case 0xc5: return { "set 0,l" }; + case 0xc6: return { "set 0,(hl)" }; + case 0xc7: return { "set 0,a" }; + case 0xc8: return { "set 1,b" }; + case 0xc9: return { "set 1,c" }; + case 0xca: return { "set 1,d" }; + case 0xcb: return { "set 1,e" }; + case 0xcc: return { "set 1,h" }; + case 0xcd: return { "set 1,l" }; + case 0xce: return { "set 1,(hl)" }; + case 0xcf: return { "set 1,a" }; + case 0xd0: return { "set 2,b" }; + case 0xd1: return { "set 2,c" }; + case 0xd2: return { "set 2,d" }; + case 0xd3: return { "set 2,e" }; + case 0xd4: return { "set 2,h" }; + case 0xd5: return { "set 2,l" }; + case 0xd6: return { "set 2,(hl)" }; + case 0xd7: return { "set 2,a" }; + case 0xd8: return { "set 3,b" }; + case 0xd9: return { "set 3,c" }; + case 0xda: return { "set 3,d" }; + case 0xdb: return { "set 3,e" }; + case 0xdc: return { "set 3,h" }; + case 0xdd: return { "set 3,l" }; + case 0xde: return { "set 3,(hl)" }; + case 0xdf: return { "set 3,a" }; + case 0xe0: return { "set 4,b" }; + case 0xe1: return { "set 4,c" }; + case 0xe2: return { "set 4,d" }; + case 0xe3: return { "set 4,e" }; + case 0xe4: return { "set 4,h" }; + case 0xe5: return { "set 4,l" }; + case 0xe6: return { "set 4,(hl)" }; + case 0xe7: return { "set 4,a" }; + case 0xe8: return { "set 5,b" }; + case 0xe9: return { "set 5,c" }; + case 0xea: return { "set 5,d" }; + case 0xeb: return { "set 5,e" }; + case 0xec: return { "set 5,h" }; + case 0xed: return { "set 5,l" }; + case 0xee: return { "set 5,(hl)" }; + case 0xef: return { "set 5,a" }; + case 0xf0: return { "set 6,b" }; + case 0xf1: return { "set 6,c" }; + case 0xf2: return { "set 6,d" }; + case 0xf3: return { "set 6,e" }; + case 0xf4: return { "set 6,h" }; + case 0xf5: return { "set 6,l" }; + case 0xf6: return { "set 6,(hl)" }; + case 0xf7: return { "set 6,a" }; + case 0xf8: return { "set 7,b" }; + case 0xf9: return { "set 7,c" }; + case 0xfa: return { "set 7,d" }; + case 0xfb: return { "set 7,e" }; + case 0xfc: return { "set 7,h" }; + case 0xfd: return { "set 7,l" }; + case 0xfe: return { "set 7,(hl)" }; + case 0xff: return { "set 7,a" }; + } + + return ""; +} + +#endif diff --git a/bsnes/gameboy/cpu/core/registers.hpp b/bsnes/gameboy/cpu/core/registers.hpp new file mode 100755 index 00000000..fbbcbd80 --- /dev/null +++ b/bsnes/gameboy/cpu/core/registers.hpp @@ -0,0 +1,101 @@ +enum { + A, F, AF, + B, C, BC, + D, E, DE, + H, L, HL, + SP, PC, +}; + +enum { + ZF, NF, HF, CF, +}; + +//register base class +//the idea here is to have all registers derive from a single base class. +//this allows construction of opcodes that can take any register as input or output, +//despite the fact that behind-the-scenes, special handling is done for eg: F, AF, HL, etc. +//registers can also be chained together: eg af = 0x0000 writes both a and f. +struct Register { + virtual operator unsigned() const = 0; + virtual unsigned operator=(unsigned x) = 0; + Register& operator=(const Register &x) { operator=((unsigned)x); return *this; } + + unsigned operator++(int) { unsigned r = *this; operator=(*this + 1); return r; } + unsigned operator--(int) { unsigned r = *this; operator=(*this - 1); return r; } + unsigned operator++() { return operator=(*this + 1); } + unsigned operator--() { return operator=(*this - 1); } + + unsigned operator |=(unsigned x) { return operator=(*this | x); } + unsigned operator ^=(unsigned x) { return operator=(*this ^ x); } + unsigned operator &=(unsigned x) { return operator=(*this & x); } + + unsigned operator<<=(unsigned x) { return operator=(*this << x); } + unsigned operator>>=(unsigned x) { return operator=(*this >> x); } + + unsigned operator +=(unsigned x) { return operator=(*this + x); } + unsigned operator -=(unsigned x) { return operator=(*this - x); } + unsigned operator *=(unsigned x) { return operator=(*this * x); } + unsigned operator /=(unsigned x) { return operator=(*this / x); } + unsigned operator %=(unsigned x) { return operator=(*this % x); } +}; + +struct Register8 : Register { + uint8 data; + operator unsigned() const { return data; } + unsigned operator=(unsigned x) { return data = x; } +}; + +struct RegisterF : Register { + bool z, n, h, c; + operator unsigned() const { return (z << 7) | (n << 6) | (h << 5) | (c << 4); } + unsigned operator=(unsigned x) { z = x & 0x80; n = x & 0x40; h = x & 0x20; c = x & 0x10; return *this; } + bool& operator[](unsigned r) { + static bool* table[] = { &z, &n, &h, &c }; + return *table[r]; + } +}; + +struct Register16 : Register { + uint16 data; + operator unsigned() const { return data; } + unsigned operator=(unsigned x) { return data = x; } +}; + +struct RegisterAF : Register { + Register8 &hi; + RegisterF &lo; + operator unsigned() const { return (hi << 8) | (lo << 0); } + unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; } + RegisterAF(Register8 &hi, RegisterF &lo) : hi(hi), lo(lo) {} +}; + +struct RegisterW : Register { + Register8 &hi, &lo; + operator unsigned() const { return (hi << 8) | (lo << 0); } + unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; } + RegisterW(Register8 &hi, Register8 &lo) : hi(hi), lo(lo) {} +}; + +struct Registers { + Register8 a; + RegisterF f; + RegisterAF af; + Register8 b; + Register8 c; + RegisterW bc; + Register8 d; + Register8 e; + RegisterW de; + Register8 h; + Register8 l; + RegisterW hl; + Register16 sp; + Register16 pc; + + Register& operator[](unsigned r) { + static Register* table[] = { &a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc }; + return *table[r]; + } + + Registers() : af(a, f), bc(b, c), de(d, e), hl(h, l) {} +} r; diff --git a/bsnes/gameboy/cpu/core/table.cpp b/bsnes/gameboy/cpu/core/table.cpp new file mode 100755 index 00000000..fa2f1112 --- /dev/null +++ b/bsnes/gameboy/cpu/core/table.cpp @@ -0,0 +1,519 @@ +#ifdef CPU_CPP + +void CPU::initialize_opcode_table() { + opcode_table[0x00] = &CPU::op_nop; + opcode_table[0x01] = &CPU::op_ld_rr_nn; + opcode_table[0x02] = &CPU::op_ld_rr_a; + opcode_table[0x03] = &CPU::op_inc_rr; + opcode_table[0x04] = &CPU::op_inc_r; + opcode_table[0x05] = &CPU::op_dec_r; + opcode_table[0x06] = &CPU::op_ld_r_n; + opcode_table[0x07] = &CPU::op_rlca; + opcode_table[0x08] = &CPU::op_ld_nn_sp; + opcode_table[0x09] = &CPU::op_add_hl_rr; + opcode_table[0x0a] = &CPU::op_ld_a_rr; + opcode_table[0x0b] = &CPU::op_dec_rr; + opcode_table[0x0c] = &CPU::op_inc_r; + opcode_table[0x0d] = &CPU::op_dec_r; + opcode_table[0x0e] = &CPU::op_ld_r_n; + opcode_table[0x0f] = &CPU::op_rrca; + opcode_table[0x10] = &CPU::op_stop; + opcode_table[0x11] = &CPU::op_ld_rr_nn; + opcode_table[0x12] = &CPU::op_ld_rr_a; + opcode_table[0x13] = &CPU::op_inc_rr; + opcode_table[0x14] = &CPU::op_inc_r; + opcode_table[0x15] = &CPU::op_dec_r; + opcode_table[0x16] = &CPU::op_ld_r_n; + opcode_table[0x17] = &CPU::op_rla; + opcode_table[0x18] = &CPU::op_jr_n; + opcode_table[0x19] = &CPU::op_add_hl_rr; + opcode_table[0x1a] = &CPU::op_ld_a_rr; + opcode_table[0x1b] = &CPU::op_dec_rr; + opcode_table[0x1c] = &CPU::op_inc_r; + opcode_table[0x1d] = &CPU::op_dec_r; + opcode_table[0x1e] = &CPU::op_ld_r_n; + opcode_table[0x1f] = &CPU::op_rra; + opcode_table[0x20] = &CPU::op_jr_f_n; + opcode_table[0x21] = &CPU::op_ld_rr_nn; + opcode_table[0x22] = &CPU::op_ldi_hl_a; + opcode_table[0x23] = &CPU::op_inc_rr; + opcode_table[0x24] = &CPU::op_inc_r; + opcode_table[0x25] = &CPU::op_dec_r; + opcode_table[0x26] = &CPU::op_ld_r_n; + opcode_table[0x27] = &CPU::op_daa; + opcode_table[0x28] = &CPU::op_jr_f_n; + opcode_table[0x29] = &CPU::op_add_hl_rr; + opcode_table[0x2a] = &CPU::op_ldi_a_hl; + opcode_table[0x2b] = &CPU::op_dec_rr; + opcode_table[0x2c] = &CPU::op_inc_r; + opcode_table[0x2d] = &CPU::op_dec_r; + opcode_table[0x2e] = &CPU::op_ld_r_n; + opcode_table[0x2f] = &CPU::op_cpl; + opcode_table[0x30] = &CPU::op_jr_f_n; + opcode_table[0x31] = &CPU::op_ld_rr_nn; + opcode_table[0x32] = &CPU::op_ldd_hl_a; + opcode_table[0x33] = &CPU::op_inc_rr; + opcode_table[0x34] = &CPU::op_inc_hl; + opcode_table[0x35] = &CPU::op_dec_hl; + opcode_table[0x36] = &CPU::op_ld_hl_n; + opcode_table[0x37] = &CPU::op_scf; + opcode_table[0x38] = &CPU::op_jr_f_n; + opcode_table[0x39] = &CPU::op_add_hl_rr; + opcode_table[0x3a] = &CPU::op_ldd_a_hl; + opcode_table[0x3b] = &CPU::op_dec_rr; + opcode_table[0x3c] = &CPU::op_inc_r; + opcode_table[0x3d] = &CPU::op_dec_r; + opcode_table[0x3e] = &CPU::op_ld_r_n; + opcode_table[0x3f] = &CPU::op_ccf; + opcode_table[0x40] = &CPU::op_ld_r_r; + opcode_table[0x41] = &CPU::op_ld_r_r; + opcode_table[0x42] = &CPU::op_ld_r_r; + opcode_table[0x43] = &CPU::op_ld_r_r; + opcode_table[0x44] = &CPU::op_ld_r_r; + opcode_table[0x45] = &CPU::op_ld_r_r; + opcode_table[0x46] = &CPU::op_ld_r_hl; + opcode_table[0x47] = &CPU::op_ld_r_r; + opcode_table[0x48] = &CPU::op_ld_r_r; + opcode_table[0x49] = &CPU::op_ld_r_r; + opcode_table[0x4a] = &CPU::op_ld_r_r; + opcode_table[0x4b] = &CPU::op_ld_r_r; + opcode_table[0x4c] = &CPU::op_ld_r_r; + opcode_table[0x4d] = &CPU::op_ld_r_r; + opcode_table[0x4e] = &CPU::op_ld_r_hl; + opcode_table[0x4f] = &CPU::op_ld_r_r; + opcode_table[0x50] = &CPU::op_ld_r_r; + opcode_table[0x51] = &CPU::op_ld_r_r; + opcode_table[0x52] = &CPU::op_ld_r_r; + opcode_table[0x53] = &CPU::op_ld_r_r; + opcode_table[0x54] = &CPU::op_ld_r_r; + opcode_table[0x55] = &CPU::op_ld_r_r; + opcode_table[0x56] = &CPU::op_ld_r_hl; + opcode_table[0x57] = &CPU::op_ld_r_r; + opcode_table[0x58] = &CPU::op_ld_r_r; + opcode_table[0x59] = &CPU::op_ld_r_r; + opcode_table[0x5a] = &CPU::op_ld_r_r; + opcode_table[0x5b] = &CPU::op_ld_r_r; + opcode_table[0x5c] = &CPU::op_ld_r_r; + opcode_table[0x5d] = &CPU::op_ld_r_r; + opcode_table[0x5e] = &CPU::op_ld_r_hl; + opcode_table[0x5f] = &CPU::op_ld_r_r; + opcode_table[0x60] = &CPU::op_ld_r_r; + opcode_table[0x61] = &CPU::op_ld_r_r; + opcode_table[0x62] = &CPU::op_ld_r_r; + opcode_table[0x63] = &CPU::op_ld_r_r; + opcode_table[0x64] = &CPU::op_ld_r_r; + opcode_table[0x65] = &CPU::op_ld_r_r; + opcode_table[0x66] = &CPU::op_ld_r_hl; + opcode_table[0x67] = &CPU::op_ld_r_r; + opcode_table[0x68] = &CPU::op_ld_r_r; + opcode_table[0x69] = &CPU::op_ld_r_r; + opcode_table[0x6a] = &CPU::op_ld_r_r; + opcode_table[0x6b] = &CPU::op_ld_r_r; + opcode_table[0x6c] = &CPU::op_ld_r_r; + opcode_table[0x6d] = &CPU::op_ld_r_r; + opcode_table[0x6e] = &CPU::op_ld_r_hl; + opcode_table[0x6f] = &CPU::op_ld_r_r; + opcode_table[0x70] = &CPU::op_ld_hl_r; + opcode_table[0x71] = &CPU::op_ld_hl_r; + opcode_table[0x72] = &CPU::op_ld_hl_r; + opcode_table[0x73] = &CPU::op_ld_hl_r; + opcode_table[0x74] = &CPU::op_ld_hl_r; + opcode_table[0x75] = &CPU::op_ld_hl_r; + opcode_table[0x76] = &CPU::op_halt; + opcode_table[0x77] = &CPU::op_ld_hl_r; + opcode_table[0x78] = &CPU::op_ld_r_r; + opcode_table[0x79] = &CPU::op_ld_r_r; + opcode_table[0x7a] = &CPU::op_ld_r_r; + opcode_table[0x7b] = &CPU::op_ld_r_r; + opcode_table[0x7c] = &CPU::op_ld_r_r; + opcode_table[0x7d] = &CPU::op_ld_r_r; + opcode_table[0x7e] = &CPU::op_ld_r_hl; + opcode_table[0x7f] = &CPU::op_ld_r_r; + opcode_table[0x80] = &CPU::op_add_a_r; + opcode_table[0x81] = &CPU::op_add_a_r; + opcode_table[0x82] = &CPU::op_add_a_r; + opcode_table[0x83] = &CPU::op_add_a_r; + opcode_table[0x84] = &CPU::op_add_a_r; + opcode_table[0x85] = &CPU::op_add_a_r; + opcode_table[0x86] = &CPU::op_add_a_hl; + opcode_table[0x87] = &CPU::op_add_a_r; + opcode_table[0x88] = &CPU::op_adc_a_r; + opcode_table[0x89] = &CPU::op_adc_a_r; + opcode_table[0x8a] = &CPU::op_adc_a_r; + opcode_table[0x8b] = &CPU::op_adc_a_r; + opcode_table[0x8c] = &CPU::op_adc_a_r; + opcode_table[0x8d] = &CPU::op_adc_a_r; + opcode_table[0x8e] = &CPU::op_adc_a_hl; + opcode_table[0x8f] = &CPU::op_adc_a_r; + opcode_table[0x90] = &CPU::op_sub_a_r; + opcode_table[0x91] = &CPU::op_sub_a_r; + opcode_table[0x92] = &CPU::op_sub_a_r; + opcode_table[0x93] = &CPU::op_sub_a_r; + opcode_table[0x94] = &CPU::op_sub_a_r; + opcode_table[0x95] = &CPU::op_sub_a_r; + opcode_table[0x96] = &CPU::op_sub_a_hl; + opcode_table[0x97] = &CPU::op_sub_a_r; + opcode_table[0x98] = &CPU::op_sbc_a_r; + opcode_table[0x99] = &CPU::op_sbc_a_r; + opcode_table[0x9a] = &CPU::op_sbc_a_r; + opcode_table[0x9b] = &CPU::op_sbc_a_r; + opcode_table[0x9c] = &CPU::op_sbc_a_r; + opcode_table[0x9d] = &CPU::op_sbc_a_r; + opcode_table[0x9e] = &CPU::op_sbc_a_hl; + opcode_table[0x9f] = &CPU::op_sbc_a_r; + opcode_table[0xa0] = &CPU::op_and_a_r; + opcode_table[0xa1] = &CPU::op_and_a_r; + opcode_table[0xa2] = &CPU::op_and_a_r; + opcode_table[0xa3] = &CPU::op_and_a_r; + opcode_table[0xa4] = &CPU::op_and_a_r; + opcode_table[0xa5] = &CPU::op_and_a_r; + opcode_table[0xa6] = &CPU::op_and_a_hl; + opcode_table[0xa7] = &CPU::op_and_a_r; + opcode_table[0xa8] = &CPU::op_xor_a_r; + opcode_table[0xa9] = &CPU::op_xor_a_r; + opcode_table[0xaa] = &CPU::op_xor_a_r; + opcode_table[0xab] = &CPU::op_xor_a_r; + opcode_table[0xac] = &CPU::op_xor_a_r; + opcode_table[0xad] = &CPU::op_xor_a_r; + opcode_table[0xae] = &CPU::op_xor_a_hl; + opcode_table[0xaf] = &CPU::op_xor_a_r; + opcode_table[0xb0] = &CPU::op_or_a_r; + opcode_table[0xb1] = &CPU::op_or_a_r; + opcode_table[0xb2] = &CPU::op_or_a_r; + opcode_table[0xb3] = &CPU::op_or_a_r; + opcode_table[0xb4] = &CPU::op_or_a_r; + opcode_table[0xb5] = &CPU::op_or_a_r; + opcode_table[0xb6] = &CPU::op_or_a_hl; + opcode_table[0xb7] = &CPU::op_or_a_r; + opcode_table[0xb8] = &CPU::op_cp_a_r; + opcode_table[0xb9] = &CPU::op_cp_a_r; + opcode_table[0xba] = &CPU::op_cp_a_r; + opcode_table[0xbb] = &CPU::op_cp_a_r; + opcode_table[0xbc] = &CPU::op_cp_a_r; + opcode_table[0xbd] = &CPU::op_cp_a_r; + opcode_table[0xbe] = &CPU::op_cp_a_hl; + opcode_table[0xbf] = &CPU::op_cp_a_r; + opcode_table[0xc0] = &CPU::op_ret_f; + opcode_table[0xc1] = &CPU::op_pop_rr; + opcode_table[0xc2] = &CPU::op_jp_f_nn; + opcode_table[0xc3] = &CPU::op_jp_nn; + opcode_table[0xc4] = &CPU::op_call_f_nn; + opcode_table[0xc5] = &CPU::op_push_rr; + opcode_table[0xc6] = &CPU::op_add_a_n; + opcode_table[0xc7] = &CPU::op_rst_n<0x00>; + opcode_table[0xc8] = &CPU::op_ret_f; + opcode_table[0xc9] = &CPU::op_ret; + opcode_table[0xca] = &CPU::op_jp_f_nn; + opcode_table[0xcb] = &CPU::op_cb; + opcode_table[0xcc] = &CPU::op_call_f_nn; + opcode_table[0xcd] = &CPU::op_call_nn; + opcode_table[0xce] = &CPU::op_adc_a_n; + opcode_table[0xcf] = &CPU::op_rst_n<0x08>; + opcode_table[0xd0] = &CPU::op_ret_f; + opcode_table[0xd1] = &CPU::op_pop_rr; + opcode_table[0xd2] = &CPU::op_jp_f_nn; + opcode_table[0xd3] = &CPU::op_xx; + opcode_table[0xd4] = &CPU::op_call_f_nn; + opcode_table[0xd5] = &CPU::op_push_rr; + opcode_table[0xd6] = &CPU::op_sub_a_n; + opcode_table[0xd7] = &CPU::op_rst_n<0x10>; + opcode_table[0xd8] = &CPU::op_ret_f; + opcode_table[0xd9] = &CPU::op_reti; + opcode_table[0xda] = &CPU::op_jp_f_nn; + opcode_table[0xdb] = &CPU::op_xx; + opcode_table[0xdc] = &CPU::op_call_f_nn; + opcode_table[0xdd] = &CPU::op_xx; + opcode_table[0xde] = &CPU::op_sbc_a_n; + opcode_table[0xdf] = &CPU::op_rst_n<0x18>; + opcode_table[0xe0] = &CPU::op_ld_ffn_a; + opcode_table[0xe1] = &CPU::op_pop_rr; + opcode_table[0xe2] = &CPU::op_ld_ffc_a; + opcode_table[0xe3] = &CPU::op_xx; + opcode_table[0xe4] = &CPU::op_xx; + opcode_table[0xe5] = &CPU::op_push_rr; + opcode_table[0xe6] = &CPU::op_and_a_n; + opcode_table[0xe7] = &CPU::op_rst_n<0x20>; + opcode_table[0xe8] = &CPU::op_add_sp_n; + opcode_table[0xe9] = &CPU::op_jp_hl; + opcode_table[0xea] = &CPU::op_ld_nn_a; + opcode_table[0xeb] = &CPU::op_xx; + opcode_table[0xec] = &CPU::op_xx; + opcode_table[0xed] = &CPU::op_xx; + opcode_table[0xee] = &CPU::op_xor_a_n; + opcode_table[0xef] = &CPU::op_rst_n<0x28>; + opcode_table[0xf0] = &CPU::op_ld_a_ffn; + opcode_table[0xf1] = &CPU::op_pop_rr; + opcode_table[0xf2] = &CPU::op_ld_a_ffc; + opcode_table[0xf3] = &CPU::op_di; + opcode_table[0xf4] = &CPU::op_xx; + opcode_table[0xf5] = &CPU::op_push_rr; + opcode_table[0xf6] = &CPU::op_or_a_n; + opcode_table[0xf7] = &CPU::op_rst_n<0x30>; + opcode_table[0xf8] = &CPU::op_ld_hl_sp_n; + opcode_table[0xf9] = &CPU::op_ld_sp_hl; + opcode_table[0xfa] = &CPU::op_ld_a_nn; + opcode_table[0xfb] = &CPU::op_ei; + opcode_table[0xfc] = &CPU::op_xx; + opcode_table[0xfd] = &CPU::op_xx; + opcode_table[0xfe] = &CPU::op_cp_a_n; + opcode_table[0xff] = &CPU::op_rst_n<0x38>; + + opcode_table_cb[0x00] = &CPU::op_rlc_r; + opcode_table_cb[0x01] = &CPU::op_rlc_r; + opcode_table_cb[0x02] = &CPU::op_rlc_r; + opcode_table_cb[0x03] = &CPU::op_rlc_r; + opcode_table_cb[0x04] = &CPU::op_rlc_r; + opcode_table_cb[0x05] = &CPU::op_rlc_r; + opcode_table_cb[0x06] = &CPU::op_rlc_hl; + opcode_table_cb[0x07] = &CPU::op_rlc_r; + opcode_table_cb[0x08] = &CPU::op_rrc_r; + opcode_table_cb[0x09] = &CPU::op_rrc_r; + opcode_table_cb[0x0a] = &CPU::op_rrc_r; + opcode_table_cb[0x0b] = &CPU::op_rrc_r; + opcode_table_cb[0x0c] = &CPU::op_rrc_r; + opcode_table_cb[0x0d] = &CPU::op_rrc_r; + opcode_table_cb[0x0e] = &CPU::op_rrc_hl; + opcode_table_cb[0x0f] = &CPU::op_rrc_r; + opcode_table_cb[0x10] = &CPU::op_rl_r; + opcode_table_cb[0x11] = &CPU::op_rl_r; + opcode_table_cb[0x12] = &CPU::op_rl_r; + opcode_table_cb[0x13] = &CPU::op_rl_r; + opcode_table_cb[0x14] = &CPU::op_rl_r; + opcode_table_cb[0x15] = &CPU::op_rl_r; + opcode_table_cb[0x16] = &CPU::op_rl_hl; + opcode_table_cb[0x17] = &CPU::op_rl_r; + opcode_table_cb[0x18] = &CPU::op_rr_r; + opcode_table_cb[0x19] = &CPU::op_rr_r; + opcode_table_cb[0x1a] = &CPU::op_rr_r; + opcode_table_cb[0x1b] = &CPU::op_rr_r; + opcode_table_cb[0x1c] = &CPU::op_rr_r; + opcode_table_cb[0x1d] = &CPU::op_rr_r; + opcode_table_cb[0x1e] = &CPU::op_rr_hl; + opcode_table_cb[0x1f] = &CPU::op_rr_r; + opcode_table_cb[0x20] = &CPU::op_sla_r; + opcode_table_cb[0x21] = &CPU::op_sla_r; + opcode_table_cb[0x22] = &CPU::op_sla_r; + opcode_table_cb[0x23] = &CPU::op_sla_r; + opcode_table_cb[0x24] = &CPU::op_sla_r; + opcode_table_cb[0x25] = &CPU::op_sla_r; + opcode_table_cb[0x26] = &CPU::op_sla_hl; + opcode_table_cb[0x27] = &CPU::op_sla_r; + opcode_table_cb[0x28] = &CPU::op_sra_r; + opcode_table_cb[0x29] = &CPU::op_sra_r; + opcode_table_cb[0x2a] = &CPU::op_sra_r; + opcode_table_cb[0x2b] = &CPU::op_sra_r; + opcode_table_cb[0x2c] = &CPU::op_sra_r; + opcode_table_cb[0x2d] = &CPU::op_sra_r; + opcode_table_cb[0x2e] = &CPU::op_sra_hl; + opcode_table_cb[0x2f] = &CPU::op_sra_r; + opcode_table_cb[0x30] = &CPU::op_swap_r; + opcode_table_cb[0x31] = &CPU::op_swap_r; + opcode_table_cb[0x32] = &CPU::op_swap_r; + opcode_table_cb[0x33] = &CPU::op_swap_r; + opcode_table_cb[0x34] = &CPU::op_swap_r; + opcode_table_cb[0x35] = &CPU::op_swap_r; + opcode_table_cb[0x36] = &CPU::op_swap_hl; + opcode_table_cb[0x37] = &CPU::op_swap_r; + opcode_table_cb[0x38] = &CPU::op_srl_r; + opcode_table_cb[0x39] = &CPU::op_srl_r; + opcode_table_cb[0x3a] = &CPU::op_srl_r; + opcode_table_cb[0x3b] = &CPU::op_srl_r; + opcode_table_cb[0x3c] = &CPU::op_srl_r; + opcode_table_cb[0x3d] = &CPU::op_srl_r; + opcode_table_cb[0x3e] = &CPU::op_srl_hl; + opcode_table_cb[0x3f] = &CPU::op_srl_r; + opcode_table_cb[0x40] = &CPU::op_bit_n_r<0, B>; + opcode_table_cb[0x41] = &CPU::op_bit_n_r<0, C>; + opcode_table_cb[0x42] = &CPU::op_bit_n_r<0, D>; + opcode_table_cb[0x43] = &CPU::op_bit_n_r<0, E>; + opcode_table_cb[0x44] = &CPU::op_bit_n_r<0, H>; + opcode_table_cb[0x45] = &CPU::op_bit_n_r<0, L>; + opcode_table_cb[0x46] = &CPU::op_bit_n_hl<0>; + opcode_table_cb[0x47] = &CPU::op_bit_n_r<0, A>; + opcode_table_cb[0x48] = &CPU::op_bit_n_r<1, B>; + opcode_table_cb[0x49] = &CPU::op_bit_n_r<1, C>; + opcode_table_cb[0x4a] = &CPU::op_bit_n_r<1, D>; + opcode_table_cb[0x4b] = &CPU::op_bit_n_r<1, E>; + opcode_table_cb[0x4c] = &CPU::op_bit_n_r<1, H>; + opcode_table_cb[0x4d] = &CPU::op_bit_n_r<1, L>; + opcode_table_cb[0x4e] = &CPU::op_bit_n_hl<1>; + opcode_table_cb[0x4f] = &CPU::op_bit_n_r<1, A>; + opcode_table_cb[0x50] = &CPU::op_bit_n_r<2, B>; + opcode_table_cb[0x51] = &CPU::op_bit_n_r<2, C>; + opcode_table_cb[0x52] = &CPU::op_bit_n_r<2, D>; + opcode_table_cb[0x53] = &CPU::op_bit_n_r<2, E>; + opcode_table_cb[0x54] = &CPU::op_bit_n_r<2, H>; + opcode_table_cb[0x55] = &CPU::op_bit_n_r<2, L>; + opcode_table_cb[0x56] = &CPU::op_bit_n_hl<2>; + opcode_table_cb[0x57] = &CPU::op_bit_n_r<2, A>; + opcode_table_cb[0x58] = &CPU::op_bit_n_r<3, B>; + opcode_table_cb[0x59] = &CPU::op_bit_n_r<3, C>; + opcode_table_cb[0x5a] = &CPU::op_bit_n_r<3, D>; + opcode_table_cb[0x5b] = &CPU::op_bit_n_r<3, E>; + opcode_table_cb[0x5c] = &CPU::op_bit_n_r<3, H>; + opcode_table_cb[0x5d] = &CPU::op_bit_n_r<3, L>; + opcode_table_cb[0x5e] = &CPU::op_bit_n_hl<3>; + opcode_table_cb[0x5f] = &CPU::op_bit_n_r<3, A>; + opcode_table_cb[0x60] = &CPU::op_bit_n_r<4, B>; + opcode_table_cb[0x61] = &CPU::op_bit_n_r<4, C>; + opcode_table_cb[0x62] = &CPU::op_bit_n_r<4, D>; + opcode_table_cb[0x63] = &CPU::op_bit_n_r<4, E>; + opcode_table_cb[0x64] = &CPU::op_bit_n_r<4, H>; + opcode_table_cb[0x65] = &CPU::op_bit_n_r<4, L>; + opcode_table_cb[0x66] = &CPU::op_bit_n_hl<4>; + opcode_table_cb[0x67] = &CPU::op_bit_n_r<4, A>; + opcode_table_cb[0x68] = &CPU::op_bit_n_r<5, B>; + opcode_table_cb[0x69] = &CPU::op_bit_n_r<5, C>; + opcode_table_cb[0x6a] = &CPU::op_bit_n_r<5, D>; + opcode_table_cb[0x6b] = &CPU::op_bit_n_r<5, E>; + opcode_table_cb[0x6c] = &CPU::op_bit_n_r<5, H>; + opcode_table_cb[0x6d] = &CPU::op_bit_n_r<5, L>; + opcode_table_cb[0x6e] = &CPU::op_bit_n_hl<5>; + opcode_table_cb[0x6f] = &CPU::op_bit_n_r<5, A>; + opcode_table_cb[0x70] = &CPU::op_bit_n_r<6, B>; + opcode_table_cb[0x71] = &CPU::op_bit_n_r<6, C>; + opcode_table_cb[0x72] = &CPU::op_bit_n_r<6, D>; + opcode_table_cb[0x73] = &CPU::op_bit_n_r<6, E>; + opcode_table_cb[0x74] = &CPU::op_bit_n_r<6, H>; + opcode_table_cb[0x75] = &CPU::op_bit_n_r<6, L>; + opcode_table_cb[0x76] = &CPU::op_bit_n_hl<6>; + opcode_table_cb[0x77] = &CPU::op_bit_n_r<6, A>; + opcode_table_cb[0x78] = &CPU::op_bit_n_r<7, B>; + opcode_table_cb[0x79] = &CPU::op_bit_n_r<7, C>; + opcode_table_cb[0x7a] = &CPU::op_bit_n_r<7, D>; + opcode_table_cb[0x7b] = &CPU::op_bit_n_r<7, E>; + opcode_table_cb[0x7c] = &CPU::op_bit_n_r<7, H>; + opcode_table_cb[0x7d] = &CPU::op_bit_n_r<7, L>; + opcode_table_cb[0x7e] = &CPU::op_bit_n_hl<7>; + opcode_table_cb[0x7f] = &CPU::op_bit_n_r<7, A>; + opcode_table_cb[0x80] = &CPU::op_res_n_r<0, B>; + opcode_table_cb[0x81] = &CPU::op_res_n_r<0, C>; + opcode_table_cb[0x82] = &CPU::op_res_n_r<0, D>; + opcode_table_cb[0x83] = &CPU::op_res_n_r<0, E>; + opcode_table_cb[0x84] = &CPU::op_res_n_r<0, H>; + opcode_table_cb[0x85] = &CPU::op_res_n_r<0, L>; + opcode_table_cb[0x86] = &CPU::op_res_n_hl<0>; + opcode_table_cb[0x87] = &CPU::op_res_n_r<0, A>; + opcode_table_cb[0x88] = &CPU::op_res_n_r<1, B>; + opcode_table_cb[0x89] = &CPU::op_res_n_r<1, C>; + opcode_table_cb[0x8a] = &CPU::op_res_n_r<1, D>; + opcode_table_cb[0x8b] = &CPU::op_res_n_r<1, E>; + opcode_table_cb[0x8c] = &CPU::op_res_n_r<1, H>; + opcode_table_cb[0x8d] = &CPU::op_res_n_r<1, L>; + opcode_table_cb[0x8e] = &CPU::op_res_n_hl<1>; + opcode_table_cb[0x8f] = &CPU::op_res_n_r<1, A>; + opcode_table_cb[0x90] = &CPU::op_res_n_r<2, B>; + opcode_table_cb[0x91] = &CPU::op_res_n_r<2, C>; + opcode_table_cb[0x92] = &CPU::op_res_n_r<2, D>; + opcode_table_cb[0x93] = &CPU::op_res_n_r<2, E>; + opcode_table_cb[0x94] = &CPU::op_res_n_r<2, H>; + opcode_table_cb[0x95] = &CPU::op_res_n_r<2, L>; + opcode_table_cb[0x96] = &CPU::op_res_n_hl<2>; + opcode_table_cb[0x97] = &CPU::op_res_n_r<2, A>; + opcode_table_cb[0x98] = &CPU::op_res_n_r<3, B>; + opcode_table_cb[0x99] = &CPU::op_res_n_r<3, C>; + opcode_table_cb[0x9a] = &CPU::op_res_n_r<3, D>; + opcode_table_cb[0x9b] = &CPU::op_res_n_r<3, E>; + opcode_table_cb[0x9c] = &CPU::op_res_n_r<3, H>; + opcode_table_cb[0x9d] = &CPU::op_res_n_r<3, L>; + opcode_table_cb[0x9e] = &CPU::op_res_n_hl<3>; + opcode_table_cb[0x9f] = &CPU::op_res_n_r<3, A>; + opcode_table_cb[0xa0] = &CPU::op_res_n_r<4, B>; + opcode_table_cb[0xa1] = &CPU::op_res_n_r<4, C>; + opcode_table_cb[0xa2] = &CPU::op_res_n_r<4, D>; + opcode_table_cb[0xa3] = &CPU::op_res_n_r<4, E>; + opcode_table_cb[0xa4] = &CPU::op_res_n_r<4, H>; + opcode_table_cb[0xa5] = &CPU::op_res_n_r<4, L>; + opcode_table_cb[0xa6] = &CPU::op_res_n_hl<4>; + opcode_table_cb[0xa7] = &CPU::op_res_n_r<4, A>; + opcode_table_cb[0xa8] = &CPU::op_res_n_r<5, B>; + opcode_table_cb[0xa9] = &CPU::op_res_n_r<5, C>; + opcode_table_cb[0xaa] = &CPU::op_res_n_r<5, D>; + opcode_table_cb[0xab] = &CPU::op_res_n_r<5, E>; + opcode_table_cb[0xac] = &CPU::op_res_n_r<5, H>; + opcode_table_cb[0xad] = &CPU::op_res_n_r<5, L>; + opcode_table_cb[0xae] = &CPU::op_res_n_hl<5>; + opcode_table_cb[0xaf] = &CPU::op_res_n_r<5, A>; + opcode_table_cb[0xb0] = &CPU::op_res_n_r<6, B>; + opcode_table_cb[0xb1] = &CPU::op_res_n_r<6, C>; + opcode_table_cb[0xb2] = &CPU::op_res_n_r<6, D>; + opcode_table_cb[0xb3] = &CPU::op_res_n_r<6, E>; + opcode_table_cb[0xb4] = &CPU::op_res_n_r<6, H>; + opcode_table_cb[0xb5] = &CPU::op_res_n_r<6, L>; + opcode_table_cb[0xb6] = &CPU::op_res_n_hl<6>; + opcode_table_cb[0xb7] = &CPU::op_res_n_r<6, A>; + opcode_table_cb[0xb8] = &CPU::op_res_n_r<7, B>; + opcode_table_cb[0xb9] = &CPU::op_res_n_r<7, C>; + opcode_table_cb[0xba] = &CPU::op_res_n_r<7, D>; + opcode_table_cb[0xbb] = &CPU::op_res_n_r<7, E>; + opcode_table_cb[0xbc] = &CPU::op_res_n_r<7, H>; + opcode_table_cb[0xbd] = &CPU::op_res_n_r<7, L>; + opcode_table_cb[0xbe] = &CPU::op_res_n_hl<7>; + opcode_table_cb[0xbf] = &CPU::op_res_n_r<7, A>; + opcode_table_cb[0xc0] = &CPU::op_set_n_r<0, B>; + opcode_table_cb[0xc1] = &CPU::op_set_n_r<0, C>; + opcode_table_cb[0xc2] = &CPU::op_set_n_r<0, D>; + opcode_table_cb[0xc3] = &CPU::op_set_n_r<0, E>; + opcode_table_cb[0xc4] = &CPU::op_set_n_r<0, H>; + opcode_table_cb[0xc5] = &CPU::op_set_n_r<0, L>; + opcode_table_cb[0xc6] = &CPU::op_set_n_hl<0>; + opcode_table_cb[0xc7] = &CPU::op_set_n_r<0, A>; + opcode_table_cb[0xc8] = &CPU::op_set_n_r<1, B>; + opcode_table_cb[0xc9] = &CPU::op_set_n_r<1, C>; + opcode_table_cb[0xca] = &CPU::op_set_n_r<1, D>; + opcode_table_cb[0xcb] = &CPU::op_set_n_r<1, E>; + opcode_table_cb[0xcc] = &CPU::op_set_n_r<1, H>; + opcode_table_cb[0xcd] = &CPU::op_set_n_r<1, L>; + opcode_table_cb[0xce] = &CPU::op_set_n_hl<1>; + opcode_table_cb[0xcf] = &CPU::op_set_n_r<1, A>; + opcode_table_cb[0xd0] = &CPU::op_set_n_r<2, B>; + opcode_table_cb[0xd1] = &CPU::op_set_n_r<2, C>; + opcode_table_cb[0xd2] = &CPU::op_set_n_r<2, D>; + opcode_table_cb[0xd3] = &CPU::op_set_n_r<2, E>; + opcode_table_cb[0xd4] = &CPU::op_set_n_r<2, H>; + opcode_table_cb[0xd5] = &CPU::op_set_n_r<2, L>; + opcode_table_cb[0xd6] = &CPU::op_set_n_hl<2>; + opcode_table_cb[0xd7] = &CPU::op_set_n_r<2, A>; + opcode_table_cb[0xd8] = &CPU::op_set_n_r<3, B>; + opcode_table_cb[0xd9] = &CPU::op_set_n_r<3, C>; + opcode_table_cb[0xda] = &CPU::op_set_n_r<3, D>; + opcode_table_cb[0xdb] = &CPU::op_set_n_r<3, E>; + opcode_table_cb[0xdc] = &CPU::op_set_n_r<3, H>; + opcode_table_cb[0xdd] = &CPU::op_set_n_r<3, L>; + opcode_table_cb[0xde] = &CPU::op_set_n_hl<3>; + opcode_table_cb[0xdf] = &CPU::op_set_n_r<3, A>; + opcode_table_cb[0xe0] = &CPU::op_set_n_r<4, B>; + opcode_table_cb[0xe1] = &CPU::op_set_n_r<4, C>; + opcode_table_cb[0xe2] = &CPU::op_set_n_r<4, D>; + opcode_table_cb[0xe3] = &CPU::op_set_n_r<4, E>; + opcode_table_cb[0xe4] = &CPU::op_set_n_r<4, H>; + opcode_table_cb[0xe5] = &CPU::op_set_n_r<4, L>; + opcode_table_cb[0xe6] = &CPU::op_set_n_hl<4>; + opcode_table_cb[0xe7] = &CPU::op_set_n_r<4, A>; + opcode_table_cb[0xe8] = &CPU::op_set_n_r<5, B>; + opcode_table_cb[0xe9] = &CPU::op_set_n_r<5, C>; + opcode_table_cb[0xea] = &CPU::op_set_n_r<5, D>; + opcode_table_cb[0xeb] = &CPU::op_set_n_r<5, E>; + opcode_table_cb[0xec] = &CPU::op_set_n_r<5, H>; + opcode_table_cb[0xed] = &CPU::op_set_n_r<5, L>; + opcode_table_cb[0xee] = &CPU::op_set_n_hl<5>; + opcode_table_cb[0xef] = &CPU::op_set_n_r<5, A>; + opcode_table_cb[0xf0] = &CPU::op_set_n_r<6, B>; + opcode_table_cb[0xf1] = &CPU::op_set_n_r<6, C>; + opcode_table_cb[0xf2] = &CPU::op_set_n_r<6, D>; + opcode_table_cb[0xf3] = &CPU::op_set_n_r<6, E>; + opcode_table_cb[0xf4] = &CPU::op_set_n_r<6, H>; + opcode_table_cb[0xf5] = &CPU::op_set_n_r<6, L>; + opcode_table_cb[0xf6] = &CPU::op_set_n_hl<6>; + opcode_table_cb[0xf7] = &CPU::op_set_n_r<6, A>; + opcode_table_cb[0xf8] = &CPU::op_set_n_r<7, B>; + opcode_table_cb[0xf9] = &CPU::op_set_n_r<7, C>; + opcode_table_cb[0xfa] = &CPU::op_set_n_r<7, D>; + opcode_table_cb[0xfb] = &CPU::op_set_n_r<7, E>; + opcode_table_cb[0xfc] = &CPU::op_set_n_r<7, H>; + opcode_table_cb[0xfd] = &CPU::op_set_n_r<7, L>; + opcode_table_cb[0xfe] = &CPU::op_set_n_hl<7>; + opcode_table_cb[0xff] = &CPU::op_set_n_r<7, A>; +} + +#endif diff --git a/bsnes/gameboy/cpu/cpu.cpp b/bsnes/gameboy/cpu/cpu.cpp new file mode 100755 index 00000000..5e00802f --- /dev/null +++ b/bsnes/gameboy/cpu/cpu.cpp @@ -0,0 +1,133 @@ +#include + +#define CPU_CPP +namespace GameBoy { + +#include "core/core.cpp" +#include "mmio/mmio.cpp" +#include "timing/timing.cpp" +CPU cpu; + +void CPU::Main() { + cpu.main(); +} + +void CPU::main() { + while(true) { + if(trace) print(disassemble(r[PC]), "\n"); + interrupt_test(); + uint8 opcode = op_read(r[PC]++); + (this->*opcode_table[opcode])(); + } +} + +void CPU::interrupt_raise(CPU::Interrupt id) { + switch(id) { + case Interrupt::Vblank: status.interrupt_request_vblank = 1; break; + case Interrupt::Stat : status.interrupt_request_stat = 1; break; + case Interrupt::Timer : status.interrupt_request_timer = 1; break; + case Interrupt::Serial: status.interrupt_request_serial = 1; break; + case Interrupt::Joypad: status.interrupt_request_joypad = 1; status.stop = false; break; + } + status.halt = false; +} + +void CPU::interrupt_test() { + if(status.ime) { + if(status.interrupt_request_vblank && status.interrupt_enable_vblank) { + status.interrupt_request_vblank = 0; + return interrupt_exec(0x0040); + } + + if(status.interrupt_request_stat && status.interrupt_enable_stat) { + status.interrupt_request_stat = 0; + return interrupt_exec(0x0048); + } + + if(status.interrupt_request_timer && status.interrupt_enable_timer) { + status.interrupt_request_timer = 0; + return interrupt_exec(0x0050); + } + + if(status.interrupt_request_serial && status.interrupt_enable_serial) { + status.interrupt_request_serial = 0; + return interrupt_exec(0x0058); + } + + if(status.interrupt_request_joypad && status.interrupt_enable_joypad) { + status.interrupt_request_joypad = 0; + return interrupt_exec(0x0060); + } + } +} + +void CPU::interrupt_exec(uint16 pc) { + status.ime = 0; + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = pc; + op_io(); + op_io(); + op_io(); +} + +void CPU::power() { + create(Main, 4 * 1024 * 1024); + + for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM + for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror) + for(unsigned n = 0xff00; n <= 0xff0f; n++) bus.mmio[n] = this; //MMIO + for(unsigned n = 0xff80; n <= 0xffff; n++) bus.mmio[n] = this; //HRAM+IE + + for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00; + for(unsigned n = 0; n < 128; n++) hram[n] = 0x00; + + r[PC] = 0x0000; + r[SP] = 0x0000; + r[AF] = 0x0000; + r[BC] = 0x0000; + r[DE] = 0x0000; + r[HL] = 0x0000; + + status.clock = 0; + status.halt = false; + status.stop = false; + + status.ime = 0; + status.timer0 = 0; + status.timer1 = 0; + status.timer2 = 0; + status.timer3 = 0; + + status.p15 = 0; + status.p14 = 0; + status.joyp = 0; + status.mlt_req = 0; + + status.div = 0; + + status.tima = 0; + + status.tma = 0; + + status.timer_enable = 0; + status.timer_clock = 0; + + status.interrupt_request_joypad = 0; + status.interrupt_request_serial = 0; + status.interrupt_request_timer = 0; + status.interrupt_request_stat = 0; + status.interrupt_request_vblank = 0; + + status.interrupt_enable_joypad = 0; + status.interrupt_enable_serial = 0; + status.interrupt_enable_timer = 0; + status.interrupt_enable_stat = 0; + status.interrupt_enable_vblank = 0; +} + +CPU::CPU() : trace(false) { + initialize_opcode_table(); +} + +} diff --git a/bsnes/gameboy/cpu/cpu.hpp b/bsnes/gameboy/cpu/cpu.hpp new file mode 100755 index 00000000..50ad7264 --- /dev/null +++ b/bsnes/gameboy/cpu/cpu.hpp @@ -0,0 +1,73 @@ +struct CPU : Processor, MMIO { + #include "core/core.hpp" + #include "mmio/mmio.hpp" + #include "timing/timing.hpp" + + bool trace; + + enum class Interrupt : unsigned { + Vblank, + Stat, + Timer, + Serial, + Joypad, + }; + + struct Status { + unsigned clock; + bool halt; + bool stop; + + bool ime; + unsigned timer0; + unsigned timer1; + unsigned timer2; + unsigned timer3; + + //$ff00 JOYP + bool p15; + bool p14; + uint8 joyp; + uint8 mlt_req; + + //$ff04 DIV + uint8 div; + + //$ff05 TIMA + uint8 tima; + + //$ff06 TMA + uint8 tma; + + //$ff07 TAC + bool timer_enable; + unsigned timer_clock; + + //$ff0f IF + bool interrupt_request_joypad; + bool interrupt_request_serial; + bool interrupt_request_timer; + bool interrupt_request_stat; + bool interrupt_request_vblank; + + //$ffff IE + bool interrupt_enable_joypad; + bool interrupt_enable_serial; + bool interrupt_enable_timer; + bool interrupt_enable_stat; + bool interrupt_enable_vblank; + } status; + + uint8 wram[8192]; + uint8 hram[128]; + + static void Main(); + void main(); + void interrupt_raise(Interrupt id); + void interrupt_test(); + void interrupt_exec(uint16 pc); + void power(); + CPU(); +}; + +extern CPU cpu; diff --git a/bsnes/gameboy/cpu/mmio/mmio.cpp b/bsnes/gameboy/cpu/mmio/mmio.cpp new file mode 100755 index 00000000..1e02bd66 --- /dev/null +++ b/bsnes/gameboy/cpu/mmio/mmio.cpp @@ -0,0 +1,131 @@ +#ifdef CPU_CPP + +void CPU::mmio_joyp_poll() { + unsigned button = 0, dpad = 0; + + button |= system.interface->input_poll((unsigned)Input::Start) << 3; + button |= system.interface->input_poll((unsigned)Input::Select) << 2; + button |= system.interface->input_poll((unsigned)Input::B) << 1; + button |= system.interface->input_poll((unsigned)Input::A) << 0; + + dpad |= system.interface->input_poll((unsigned)Input::Down) << 3; + dpad |= system.interface->input_poll((unsigned)Input::Up) << 2; + dpad |= system.interface->input_poll((unsigned)Input::Left) << 1; + dpad |= system.interface->input_poll((unsigned)Input::Right) << 0; + + status.joyp = 0x0f; + if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req; + if(status.p15 == 0) status.joyp &= button ^ 0x0f; + if(status.p14 == 0) status.joyp &= dpad ^ 0x0f; + if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad); +} + +uint8 CPU::mmio_read(uint16 addr) { + if(addr >= 0xc000 && addr <= 0xdfff) return wram[addr & 0x1fff]; + if(addr >= 0xe000 && addr <= 0xfdff) return wram[addr & 0x1fff]; + if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f]; + + if(addr == 0xff00) { //JOYP + return (status.p15 << 5) + | (status.p14 << 4) + | (status.joyp << 0); + } + + if(addr == 0xff04) { //DIV + return status.div; + } + + if(addr == 0xff05) { //TIMA + return status.tima; + } + + if(addr == 0xff06) { //TMA + return status.tma; + } + + if(addr == 0xff07) { //TAC + return (status.timer_enable << 2) + | (status.timer_clock << 0); + } + + if(addr == 0xff0f) { //IF + return (status.interrupt_request_joypad << 4) + | (status.interrupt_request_serial << 3) + | (status.interrupt_request_timer << 2) + | (status.interrupt_request_stat << 1) + | (status.interrupt_request_vblank << 0); + } + + if(addr == 0xffff) { //IE + return (status.interrupt_enable_joypad << 4) + | (status.interrupt_enable_serial << 3) + | (status.interrupt_enable_timer << 2) + | (status.interrupt_enable_stat << 1) + | (status.interrupt_enable_vblank << 0); + } + + return 0x00; +} + +void CPU::mmio_write(uint16 addr, uint8 data) { + if(addr >= 0xc000 && addr <= 0xdfff) { wram[addr & 0x1fff] = data; return; } + if(addr >= 0xe000 && addr <= 0xfdff) { wram[addr & 0x1fff] = data; return; } + if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; } + + if(addr == 0xff00) { //JOYP + status.p15 = data & 0x20; + status.p14 = data & 0x10; + system.interface->joyp_write(status.p15, status.p14); + mmio_joyp_poll(); + return; + } + + if(addr == 0xff01) { //SB + return; + } + + if(addr == 0xff02) { //SC + return; + } + + if(addr == 0xff04) { //DIV + status.div = 0; + return; + } + + if(addr == 0xff05) { //TIMA + status.tima = data; + return; + } + + if(addr == 0xff06) { //TMA + status.tma = data; + return; + } + + if(addr == 0xff07) { //TAC + status.timer_enable = data & 0x04; + status.timer_clock = data & 0x03; + return; + } + + if(addr == 0xff0f) { //IF + status.interrupt_request_joypad = data & 0x10; + status.interrupt_request_serial = data & 0x08; + status.interrupt_request_timer = data & 0x04; + status.interrupt_request_stat = data & 0x02; + status.interrupt_request_vblank = data & 0x01; + return; + } + + if(addr == 0xffff) { //IE + status.interrupt_enable_joypad = data & 0x10; + status.interrupt_enable_serial = data & 0x08; + status.interrupt_enable_timer = data & 0x04; + status.interrupt_enable_stat = data & 0x02; + status.interrupt_enable_vblank = data & 0x01; + return; + } +} + +#endif diff --git a/bsnes/gameboy/cpu/mmio/mmio.hpp b/bsnes/gameboy/cpu/mmio/mmio.hpp new file mode 100755 index 00000000..bc9eb8ba --- /dev/null +++ b/bsnes/gameboy/cpu/mmio/mmio.hpp @@ -0,0 +1,3 @@ +void mmio_joyp_poll(); +uint8 mmio_read(uint16 addr); +void mmio_write(uint16 addr, uint8 data); diff --git a/bsnes/gameboy/cpu/timing/opcode.cpp b/bsnes/gameboy/cpu/timing/opcode.cpp new file mode 100755 index 00000000..b952e3d6 --- /dev/null +++ b/bsnes/gameboy/cpu/timing/opcode.cpp @@ -0,0 +1,18 @@ +#ifdef CPU_CPP + +void CPU::op_io() { + add_clocks(4); +} + +uint8 CPU::op_read(uint16 addr) { + uint8 r = bus.read(addr); + add_clocks(4); + return r; +} + +void CPU::op_write(uint16 addr, uint8 data) { + bus.write(addr, data); + add_clocks(4); +} + +#endif diff --git a/bsnes/gameboy/cpu/timing/timing.cpp b/bsnes/gameboy/cpu/timing/timing.cpp new file mode 100755 index 00000000..3a400d06 --- /dev/null +++ b/bsnes/gameboy/cpu/timing/timing.cpp @@ -0,0 +1,81 @@ +//4194304hz (4 * 1024 * 1024) +//70224 clocks/frame +// 456 clocks/scanline +// 154 scanlines/frame + +//4194304 / 4096 = 1024 +//4194304 / 262144 = 16 +//4194304 / 65536 = 64 +//4394304 / 16384 = 256 + +#ifdef CPU_CPP + +#include "opcode.cpp" + +void CPU::add_clocks(unsigned clocks) { + system.clocks_executed += clocks; + scheduler.exit(); + + status.clock += clocks; + if(status.clock >= 4 * 1024 * 1024) { + status.clock -= 4 * 1024 * 1024; + cartridge.mbc3.second(); + } + + status.timer0 += clocks; + if(status.timer0 >= 16) timer_stage0(); + + cpu.clock += clocks; + if(cpu.clock >= 0) co_switch(scheduler.active_thread = lcd.thread); +} + +void CPU::timer_stage0() { //262144hz + if(status.timer_enable && status.timer_clock == 1) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } + + status.timer0 -= 16; + if(++status.timer1 >= 4) timer_stage1(); +} + +void CPU::timer_stage1() { // 65536hz + if(status.timer_enable && status.timer_clock == 2) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } + + status.timer1 -= 4; + if(++status.timer2 >= 4) timer_stage2(); +} + +void CPU::timer_stage2() { // 16384hz + if(status.timer_enable && status.timer_clock == 3) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } + + status.div++; + + status.timer2 -= 4; + if(++status.timer3 >= 4) timer_stage3(); +} + +void CPU::timer_stage3() { // 4096hz + if(status.timer_enable && status.timer_clock == 0) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } + + status.timer3 -= 4; +} + +#endif diff --git a/bsnes/gameboy/cpu/timing/timing.hpp b/bsnes/gameboy/cpu/timing/timing.hpp new file mode 100755 index 00000000..7362f02e --- /dev/null +++ b/bsnes/gameboy/cpu/timing/timing.hpp @@ -0,0 +1,10 @@ +void add_clocks(unsigned clocks); +void timer_stage0(); +void timer_stage1(); +void timer_stage2(); +void timer_stage3(); + +//opcode.cpp +void op_io(); +uint8 op_read(uint16 addr); +void op_write(uint16 addr, uint8 data); diff --git a/bsnes/gameboy/gameboy.hpp b/bsnes/gameboy/gameboy.hpp new file mode 100755 index 00000000..4a5e6773 --- /dev/null +++ b/bsnes/gameboy/gameboy.hpp @@ -0,0 +1,52 @@ +//bgameboy +//author: byuu +//project started: 2010-12-27 + +namespace GameBoy { + namespace Info { + static const char Name[] = "bgameboy"; + static const char Version[] = "000.10"; + } +} + +#include + +#include +#include +#include +#include +using namespace nall; + +namespace GameBoy { + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + + struct Processor { + cothread_t thread; + unsigned frequency; + int64 clock; + + inline void create(void (*entrypoint_)(), unsigned frequency_) { + if(thread) co_delete(thread); + thread = co_create(65536 * sizeof(void*), entrypoint_); + frequency = frequency_; + clock = 0; + } + + inline Processor() : thread(0) {} + }; + + #include + #include + #include + #include + #include + #include +}; diff --git a/bsnes/gameboy/interface/interface.hpp b/bsnes/gameboy/interface/interface.hpp new file mode 100755 index 00000000..372cbd7f --- /dev/null +++ b/bsnes/gameboy/interface/interface.hpp @@ -0,0 +1,11 @@ +class Interface { +public: + virtual void joyp_write(bool p15, bool p14) {} + + virtual void video_refresh(const uint8_t *data) {} + virtual void audio_sample(signed left, signed right) {} + virtual void input_poll() {} + virtual bool input_poll(unsigned id) {} + + virtual void message(const string &text) { print(text, "\n"); } +}; diff --git a/bsnes/gameboy/lcd/lcd.cpp b/bsnes/gameboy/lcd/lcd.cpp new file mode 100755 index 00000000..33143362 --- /dev/null +++ b/bsnes/gameboy/lcd/lcd.cpp @@ -0,0 +1,224 @@ +#include + +#define LCD_CPP +namespace GameBoy { + +#include "mmio/mmio.cpp" +LCD lcd; + +void LCD::Main() { + lcd.main(); +} + +void LCD::main() { + while(true) { + add_clocks(4); + + if(status.lx == 320) { + if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat); + } + } +} + +void LCD::add_clocks(unsigned clocks) { + status.lx += clocks; + if(status.lx >= 456) scanline(); + + cpu.clock -= clocks; + if(cpu.clock <= 0) co_switch(scheduler.active_thread = cpu.thread); +} + +void LCD::scanline() { + status.lx -= 456; + if(++status.ly == 154) frame(); + + if(status.interrupt_lyc == true) { + if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat); + } + + if(status.ly < 144) render(); + + if(status.ly == 144) { + cpu.interrupt_raise(CPU::Interrupt::Vblank); + if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat); + } +} + +void LCD::frame() { + system.interface->video_refresh(screen); + system.interface->input_poll(); + cpu.mmio_joyp_poll(); + + status.ly = 0; + scheduler.exit(); +} + +void LCD::render() { + for(unsigned n = 0; n < 160; n++) line[n] = 0x00; + + if(status.display_enable == true) { + if(status.bg_enable == true) render_bg(); + if(status.window_display_enable == true) render_window(); + if(status.obj_enable == true) render_obj(); + } + + uint8_t *output = screen + status.ly * 160; + for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55; +} + +uint16 LCD::read_tile(bool select, unsigned x, unsigned y) { + unsigned tmaddr = 0x1800 + (select << 10), tdaddr; + tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; + if(status.bg_tiledata_select == 0) { + tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4); + } else { + tdaddr = 0x0000 + (vram[tmaddr] << 4); + } + tdaddr += (y & 7) << 1; + return (vram[tdaddr + 0] << 0) | (vram[tdaddr + 1] << 8); +} + +void LCD::render_bg() { + unsigned iy = (status.ly + status.scy) & 255; + unsigned ix = status.scx, tx = ix & 7; + unsigned data = read_tile(status.bg_tilemap_select, ix, iy); + + for(unsigned ox = 0; ox < 160; ox++) { + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + line[ox] = status.bgp[palette]; + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + + if(tx == 0) data = read_tile(status.bg_tilemap_select, ix, iy); + } +} + +void LCD::render_window() { + if(status.ly - status.wy >= 144U) return; + unsigned iy = status.ly - status.wy; + unsigned ix = (status.wx - 7) & 255, tx = ix & 7; + unsigned data = read_tile(status.window_tilemap_select, ix, iy); + + for(unsigned ox = 0; ox < 160; ox++) { + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + if(ox - (status.wx - 7) < 160U) line[ox] = status.bgp[palette]; + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + + if(tx == 0) data = read_tile(status.window_tilemap_select, ix, iy); + } +} + +void LCD::render_obj() { + unsigned obj_size = (status.obj_size == 0 ? 8 : 16); + + unsigned sprite[10], sprites = 0; + + //find first ten sprites on this scanline + for(unsigned s = 0; s < 40; s++) { + unsigned sy = oam[(s << 2) + 0] - 16; + unsigned sx = oam[(s << 2) + 1] - 8; + + sy = status.ly - sy; + if(sy >= obj_size) continue; + + sprite[sprites++] = s; + if(sprites == 10) break; + } + + //sort by X-coordinate, when equal, lower address comes first + for(unsigned x = 0; x < sprites; x++) { + for(unsigned y = x + 1; y < sprites; y++) { + signed sx = oam[(sprite[x] << 2) + 1] - 8; + signed sy = oam[(sprite[y] << 2) + 1] - 8; + if(sy < sx) { + sprite[x] ^= sprite[y]; + sprite[y] ^= sprite[x]; + sprite[x] ^= sprite[y]; + } + } + } + + //render backwards, so that first sprite has highest priority + for(signed s = sprites - 1; s >= 0; s--) { + unsigned n = sprite[s] << 2; + unsigned sy = oam[n + 0] - 16; + unsigned sx = oam[n + 1] - 8; + unsigned tile = oam[n + 2]; + unsigned attribute = oam[n + 3]; + + sy = status.ly - sy; + if(sy >= obj_size) continue; + if(attribute & 0x40) sy ^= (obj_size - 1); + + unsigned tdaddr = (tile << 4) + (sy << 1); + uint8 d0 = vram[tdaddr + 0]; + uint8 d1 = vram[tdaddr + 1]; + unsigned xflip = attribute & 0x20 ? 7 : 0; + + for(unsigned tx = 0; tx < 8; tx++) { + uint8 palette = ((d0 & (0x80 >> tx)) ? 1 : 0) + | ((d1 & (0x80 >> tx)) ? 2 : 0); + if(palette == 0) continue; + + palette = status.obp[(bool)(attribute & 0x10)][palette]; + unsigned ox = sx + (tx ^ xflip); + + if(ox <= 159) { + if(attribute & 0x80) { + if(line[ox] > 0) continue; + } + line[ox] = palette; + } + } + } +} + +void LCD::power() { + create(Main, 4 * 1024 * 1024); + + for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM + for(unsigned n = 0xff40; n <= 0xff4b; n++) bus.mmio[n] = this; //MMIO + for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM + + for(unsigned n = 0; n < 8192; n++) vram[n] = 0x00; + for(unsigned n = 0; n < 160; n++) oam [n] = 0x00; + + for(unsigned n = 0; n < 160 * 144; n++) screen[n] = 0x00; + + status.lx = 0; + + status.display_enable = 0; + status.window_tilemap_select = 0; + status.window_display_enable = 0; + status.bg_tiledata_select = 0; + status.bg_tilemap_select = 0; + status.obj_size = 0; + status.obj_enable = 0; + status.bg_enable = 0; + + status.interrupt_lyc = 0; + status.interrupt_oam = 0; + status.interrupt_vblank = 0; + status.interrupt_hblank = 0; + + status.scy = 0; + status.scx = 0; + status.ly = 0; + status.lyc = 0; + + for(unsigned n = 0; n < 4; n++) { + status.bgp[n] = n; + status.obp[0][n] = n; + status.obp[1][n] = n; + } + + status.wy = 0; + status.wx = 0; +} + +} diff --git a/bsnes/gameboy/lcd/lcd.hpp b/bsnes/gameboy/lcd/lcd.hpp new file mode 100755 index 00000000..a3c72525 --- /dev/null +++ b/bsnes/gameboy/lcd/lcd.hpp @@ -0,0 +1,68 @@ +struct LCD : Processor, MMIO { + #include "mmio/mmio.hpp" + + struct Status { + unsigned lx; + + //$ff40 LCDC + bool display_enable; + bool window_tilemap_select; + bool window_display_enable; + bool bg_tiledata_select; + bool bg_tilemap_select; + bool obj_size; + bool obj_enable; + bool bg_enable; + + //$ff41 STAT + bool interrupt_lyc; + bool interrupt_oam; + bool interrupt_vblank; + bool interrupt_hblank; + + //$ff42 SCY + uint8 scy; + + //$ff43 SCX + uint8 scx; + + //$ff44 LY + uint8 ly; + + //$ff45 LYC + uint8 lyc; + + //$ff47 BGP + uint8 bgp[4]; + + //$ff48 OBP0 + //$ff49 OBP1 + uint8 obp[2][4]; + + //$ff4a WY + uint8 wy; + + //$ff4b WX + uint8 wx; + } status; + + uint8 screen[160 * 144]; + uint8 vram[8192]; + uint8 oam[160]; + uint8 line[160]; + + static void Main(); + void main(); + void add_clocks(unsigned clocks); + void scanline(); + void frame(); + void render(); + uint16 read_tile(bool select, unsigned x, unsigned y); + void render_bg(); + void render_window(); + void render_obj(); + + void power(); +}; + +extern LCD lcd; diff --git a/bsnes/gameboy/lcd/mmio/mmio.cpp b/bsnes/gameboy/lcd/mmio/mmio.cpp new file mode 100755 index 00000000..aafef096 --- /dev/null +++ b/bsnes/gameboy/lcd/mmio/mmio.cpp @@ -0,0 +1,164 @@ +#ifdef LCD_CPP + +uint8 LCD::mmio_read(uint16 addr) { + if(addr >= 0x8000 && addr <= 0x9fff) return vram[addr & 0x1fff]; + if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff]; + + if(addr == 0xff40) { //LCDC + return (status.display_enable << 7) + | (status.window_tilemap_select << 6) + | (status.window_display_enable << 5) + | (status.bg_tiledata_select << 4) + | (status.bg_tilemap_select << 3) + | (status.obj_size << 2) + | (status.obj_enable << 1) + | (status.bg_enable << 0); + } + + if(addr == 0xff41) { //STAT + unsigned mode; + if(status.ly >= 144) mode = 1; //Vblank + else if(status.lx >= 320) mode = 0; //Hblank + else mode = 3; //LCD transfer + + return (status.interrupt_lyc << 6) + | (status.interrupt_oam << 5) + | (status.interrupt_vblank << 4) + | (status.interrupt_hblank << 3) + | ((status.ly == status.lyc) << 2) + | (mode << 0); + } + + if(addr == 0xff42) { //SCY + return status.scy; + } + + if(addr == 0xff43) { //SCX + return status.scx; + } + + if(addr == 0xff44) { //LY + return status.ly; + } + + if(addr == 0xff45) { //LYC + return status.lyc; + } + + if(addr == 0xff47) { //BGP + return (status.bgp[3] << 6) + | (status.bgp[2] << 4) + | (status.bgp[1] << 2) + | (status.bgp[0] << 0); + } + + if(addr == 0xff48) { //OBP0 + return (status.obp[0][3] << 6) + | (status.obp[0][2] << 4) + | (status.obp[0][1] << 2) + | (status.obp[0][0] << 0); + } + + if(addr == 0xff49) { //OBP1 + return (status.obp[1][3] << 6) + | (status.obp[1][2] << 4) + | (status.obp[1][1] << 2) + | (status.obp[1][0] << 0); + } + + if(addr == 0xff4a) { //WY + return status.wy; + } + + if(addr == 0xff4b) { //WX + return status.wx; + } + + return 0x00; +} + +void LCD::mmio_write(uint16 addr, uint8 data) { + if(addr >= 0x8000 && addr <= 0x9fff) { vram[addr & 0x1fff] = data; return; } + if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; } + + if(addr == 0xff40) { //LCDC + status.display_enable = data & 0x80; + status.window_tilemap_select = data & 0x40; + status.window_display_enable = data & 0x20; + status.bg_tiledata_select = data & 0x10; + status.bg_tilemap_select = data & 0x08; + status.obj_size = data & 0x04; + status.obj_enable = data & 0x02; + status.bg_enable = data & 0x01; + return; + } + + if(addr == 0xff41) { //STAT + status.interrupt_lyc = data & 0x40; + status.interrupt_oam = data & 0x20; + status.interrupt_vblank = data & 0x10; + status.interrupt_hblank = data & 0x08; + return; + } + + if(addr == 0xff42) { //SCY + status.scy = data; + return; + } + + if(addr == 0xff43) { //SCX + status.scx = data; + return; + } + + if(addr == 0xff44) { //LY + status.ly = 0; + return; + } + + if(addr == 0xff45) { //LYC + status.lyc = data; + return; + } + + if(addr == 0xff46) { //DMA + for(unsigned n = 0x00; n <= 0x9f; n++) bus.write(0xfe00 + n, bus.read((data << 8) + n)); + return; + } + + if(addr == 0xff47) { //BGP + status.bgp[3] = (data >> 6) & 3; + status.bgp[2] = (data >> 4) & 3; + status.bgp[1] = (data >> 2) & 3; + status.bgp[0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff48) { //OBP0 + status.obp[0][3] = (data >> 6) & 3; + status.obp[0][2] = (data >> 4) & 3; + status.obp[0][1] = (data >> 2) & 3; + status.obp[0][0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff49) { //OBP1 + status.obp[1][3] = (data >> 6) & 3; + status.obp[1][2] = (data >> 4) & 3; + status.obp[1][1] = (data >> 2) & 3; + status.obp[1][0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff4a) { //WY + status.wy = data; + return; + } + + if(addr == 0xff4b) { //WX + status.wx = data; + return; + } +} + +#endif diff --git a/bsnes/gameboy/lcd/mmio/mmio.hpp b/bsnes/gameboy/lcd/mmio/mmio.hpp new file mode 100755 index 00000000..92b8f614 --- /dev/null +++ b/bsnes/gameboy/lcd/mmio/mmio.hpp @@ -0,0 +1,2 @@ +uint8 mmio_read(uint16 addr); +void mmio_write(uint16 addr, uint8 data); diff --git a/bsnes/gameboy/memory/memory.cpp b/bsnes/gameboy/memory/memory.cpp new file mode 100755 index 00000000..62ffe162 --- /dev/null +++ b/bsnes/gameboy/memory/memory.cpp @@ -0,0 +1,60 @@ +#include + +#define MEMORY_CPP +namespace GameBoy { + +Unmapped unmapped; +Bus bus; + +uint8_t& Memory::operator[](unsigned addr) { + return data[addr]; +} + +void Memory::allocate(unsigned size_) { + free(); + size = size_; + data = new uint8_t[size](); +} + +void Memory::copy(const uint8_t *data_, unsigned size_) { + free(); + size = size_; + data = new uint8_t[size]; + memcpy(data, data_, size); +} + +void Memory::free() { + if(data) { + delete[] data; + data = 0; + } +} + +Memory::Memory() { + data = 0; + size = 0; +} + +Memory::~Memory() { + free(); +} + +// + +uint8 Bus::read(uint16 addr) { + return mmio[addr]->mmio_read(addr); +} + +void Bus::write(uint16 addr, uint8 data) { + mmio[addr]->mmio_write(addr, data); +} + +void Bus::power() { + for(unsigned n = 0; n < 65536; n++) mmio[n] = &unmapped; + reset(); +} + +void Bus::reset() { +} + +} diff --git a/bsnes/gameboy/memory/memory.hpp b/bsnes/gameboy/memory/memory.hpp new file mode 100755 index 00000000..0b9ca99c --- /dev/null +++ b/bsnes/gameboy/memory/memory.hpp @@ -0,0 +1,36 @@ +struct Memory { + uint8_t *data; + unsigned size; + + uint8_t& operator[](unsigned addr); + void allocate(unsigned size); + void copy(const uint8_t *data, unsigned size); + void free(); + Memory(); + ~Memory(); +}; + +struct MMIO { + virtual uint8 mmio_read(uint16 addr) = 0; + virtual void mmio_write(uint16 addr, uint8 data) = 0; +}; + +struct Unmapped : MMIO { + uint8 mmio_read(uint16) { return 0x00; } + void mmio_write(uint16, uint8) {} +}; + +struct Bus { + Memory cartrom; + Memory cartram; + + MMIO *mmio[65536]; + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); + + void power(); + void reset(); +}; + +extern Unmapped unmapped; +extern Bus bus; diff --git a/bsnes/gameboy/scheduler/scheduler.cpp b/bsnes/gameboy/scheduler/scheduler.cpp new file mode 100755 index 00000000..2f32cea5 --- /dev/null +++ b/bsnes/gameboy/scheduler/scheduler.cpp @@ -0,0 +1,33 @@ +#include + +#define SCHEDULER_CPP +namespace GameBoy { + +Scheduler scheduler; + +void Scheduler::enter() { + host_thread = co_active(); + co_switch(active_thread); +} + +void Scheduler::exit() { + active_thread = co_active(); + co_switch(host_thread); +} + +void Scheduler::swapto(Processor &p) { + active_thread = p.thread; + co_switch(active_thread); +} + +void Scheduler::init() { + host_thread = co_active(); + active_thread = cpu.thread; +} + +Scheduler::Scheduler() { + host_thread = 0; + active_thread = 0; +} + +} diff --git a/bsnes/gameboy/scheduler/scheduler.hpp b/bsnes/gameboy/scheduler/scheduler.hpp new file mode 100755 index 00000000..69337acf --- /dev/null +++ b/bsnes/gameboy/scheduler/scheduler.hpp @@ -0,0 +1,13 @@ +struct Scheduler { + cothread_t host_thread; + cothread_t active_thread; + + void enter(); + void exit(); + void swapto(Processor&); + + void init(); + Scheduler(); +}; + +extern Scheduler scheduler; diff --git a/bsnes/gameboy/system/bootrom-dmg.cpp b/bsnes/gameboy/system/bootrom-dmg.cpp new file mode 100755 index 00000000..5fb38844 --- /dev/null +++ b/bsnes/gameboy/system/bootrom-dmg.cpp @@ -0,0 +1,23 @@ +#ifdef SYSTEM_CPP + +//MD5SUM = 32fbbd84168d3482956eb3c5051637f5 +const uint8_t System::BootROM::dmg[256] = { + 0x31,0xfe,0xff,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,0x21,0x26,0xff,0x0e, + 0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,0x77,0x3e,0xfc,0xe0, + 0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1a,0xcd,0x95,0x00,0xcd,0x96,0x00,0x13,0x7b, + 0xfe,0x34,0x20,0xf3,0x11,0xd8,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9, + 0x3e,0x19,0xea,0x10,0x99,0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20, + 0xf9,0x2e,0x0f,0x18,0xf3,0x67,0x3e,0x64,0x57,0xe0,0x42,0x3e,0x91,0xe0,0x40,0x04, + 0x1e,0x02,0x0e,0x0c,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x0d,0x20,0xf7,0x1d,0x20,0xf2, + 0x0e,0x13,0x24,0x7c,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x06, + 0x7b,0xe2,0x0c,0x3e,0x87,0xe2,0xf0,0x42,0x90,0xe0,0x42,0x15,0x20,0xd2,0x05,0x20, + 0x4f,0x16,0x20,0x18,0xcb,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17, + 0x05,0x20,0xf5,0x22,0x23,0x22,0x23,0xc9,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b, + 0x03,0x73,0x00,0x83,0x00,0x0c,0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e, + 0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc, + 0xdd,0xdc,0x99,0x9f,0xbb,0xb9,0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c, + 0x21,0x04,0x01,0x11,0xa8,0x00,0x1a,0x13,0xbe,0x20,0xfe,0x23,0x7d,0xfe,0x34,0x20, + 0xf5,0x06,0x19,0x78,0x86,0x23,0x05,0x20,0xfb,0x86,0x20,0xfe,0x3e,0x01,0xe0,0x50, +}; + +#endif diff --git a/bsnes/gameboy/system/bootrom-sgb.cpp b/bsnes/gameboy/system/bootrom-sgb.cpp new file mode 100755 index 00000000..ac58529d --- /dev/null +++ b/bsnes/gameboy/system/bootrom-sgb.cpp @@ -0,0 +1,23 @@ +#ifdef SYSTEM_CPP + +//MD5SUM = d574d4f9c12f305074798f54c091a8b4 +const uint8_t System::BootROM::sgb[256] = { + 0x31,0xfe,0xff,0x3e,0x30,0xe0,0x00,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb, + 0x21,0x26,0xff,0x0e,0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77, + 0x77,0x3e,0xfc,0xe0,0x47,0x21,0x5f,0xc0,0x0e,0x08,0xaf,0x32,0x0d,0x20,0xfc,0x11, + 0x4f,0x01,0x3e,0xfb,0x0e,0x06,0xf5,0x06,0x00,0x1a,0x1b,0x32,0x80,0x47,0x0d,0x20, + 0xf8,0x32,0xf1,0x32,0x0e,0x0e,0xd6,0x02,0xfe,0xef,0x20,0xea,0x11,0x04,0x01,0x21, + 0x10,0x80,0x1a,0xcd,0xd3,0x00,0xcd,0xd4,0x00,0x13,0x7b,0xfe,0x34,0x20,0xf3,0x11, + 0xe6,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0x3e,0x19,0xea,0x10,0x99, + 0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3, + 0x3e,0x91,0xe0,0x40,0x21,0x00,0xc0,0x0e,0x00,0x3e,0x00,0xe2,0x3e,0x30,0xe2,0x06, + 0x10,0x1e,0x08,0x2a,0x57,0xcb,0x42,0x3e,0x10,0x20,0x02,0x3e,0x20,0xe2,0x3e,0x30, + 0xe2,0xcb,0x1a,0x1d,0x20,0xef,0x05,0x20,0xe8,0x3e,0x20,0xe2,0x3e,0x30,0xe2,0xcd, + 0xc2,0x00,0x7d,0xfe,0x60,0x20,0xd2,0x0e,0x13,0x3e,0xc1,0xe2,0x0c,0x3e,0x07,0xe2, + 0x18,0x3a,0x16,0x04,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x1e,0x00,0x1d,0x20,0xfd,0x15, + 0x20,0xf2,0xc9,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,0x05,0x20, + 0xf5,0x22,0x23,0x22,0x23,0xc9,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x01,0xe0,0x50, +}; + +#endif diff --git a/bsnes/gameboy/system/system.cpp b/bsnes/gameboy/system/system.cpp new file mode 100755 index 00000000..4e959d4b --- /dev/null +++ b/bsnes/gameboy/system/system.cpp @@ -0,0 +1,44 @@ +#include + +#define SYSTEM_CPP +namespace GameBoy { + +#include "bootrom-dmg.cpp" +#include "bootrom-sgb.cpp" +System system; + +uint8 System::mmio_read(uint16 addr) { + if((addr & 0xff00) == 0x0000) { + return BootROM::sgb[addr]; + } + return 0x00; +} + +void System::mmio_write(uint16 addr, uint8 data) { + if(addr == 0xff50) { + if(data == 0x01) cartridge.map(); + } +} + +void System::init(Interface *interface_) { + interface = interface_; +} + +void System::power() { + bus.power(); + cartridge.power(); + cpu.power(); + lcd.power(); + scheduler.init(); + + for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this; + bus.mmio[0xff50] = this; + + system.clocks_executed = 0; +} + +void System::run() { + scheduler.enter(); +} + +} diff --git a/bsnes/gameboy/system/system.hpp b/bsnes/gameboy/system/system.hpp new file mode 100755 index 00000000..7d54d529 --- /dev/null +++ b/bsnes/gameboy/system/system.hpp @@ -0,0 +1,26 @@ +class Interface; + +enum class Input : unsigned { + Up, Down, Left, Right, B, A, Select, Start, +}; + +struct System : MMIO { + struct BootROM { + static const uint8 dmg[256]; + static const uint8 sgb[256]; + } bootROM; + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + + void init(Interface*); + void power(); + void run(); + + Interface *interface; + unsigned clocks_executed; +}; + +#include + +extern System system; diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index b3ac7ea4..b9d9bcda 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -1,9 +1,8 @@ -snes_objects := libco -snes_objects += snes-system +snes_objects := snes-system snes_objects += snes-cartridge snes-cheat snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-cpu snes-smp snes-dsp snes-ppu -snes_objects += snes-supergameboy snes-superfx snes-sa1 snes-upd77c25 +snes_objects += snes-icd2 snes-superfx snes-sa1 snes-upd77c25 snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4 snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018 snes_objects += snes-msu1 snes-serial @@ -29,7 +28,6 @@ else ifeq ($(profile),performance) snesppu := $(snes)/alt/ppu-performance endif -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/) @@ -43,21 +41,21 @@ obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/) obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(call rwilddcard,$(snes)/cartridge/) obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(call rwildcard,$(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-upd77c25.o : $(snes)/chip/upd77c25/upd77c25.cpp $(call rwildcard,$(snes)/chip/upd77c25/) -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-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/* +obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/) +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-upd77c25.o: $(snes)/chip/upd77c25/upd77c25.cpp $(call rwildcard,$(snes)/chip/upd77c25/) +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-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 # diff --git a/bsnes/snes/alt/cpu/cpu.cpp b/bsnes/snes/alt/cpu/cpu.cpp index 6f4f9ca0..9eb729f5 100755 --- a/bsnes/snes/alt/cpu/cpu.cpp +++ b/bsnes/snes/alt/cpu/cpu.cpp @@ -1,4 +1,4 @@ -#include +#include #define CPU_CPP namespace SNES { diff --git a/bsnes/snes/alt/dsp/dsp.cpp b/bsnes/snes/alt/dsp/dsp.cpp index a5ea8956..42b1beb5 100755 --- a/bsnes/snes/alt/dsp/dsp.cpp +++ b/bsnes/snes/alt/dsp/dsp.cpp @@ -1,4 +1,4 @@ -#include +#include #define DSP_CPP namespace SNES { diff --git a/bsnes/snes/alt/ppu-compatibility/ppu.cpp b/bsnes/snes/alt/ppu-compatibility/ppu.cpp index 768ca4c7..f560108b 100755 --- a/bsnes/snes/alt/ppu-compatibility/ppu.cpp +++ b/bsnes/snes/alt/ppu-compatibility/ppu.cpp @@ -1,4 +1,4 @@ -#include +#include #define PPU_CPP namespace SNES { diff --git a/bsnes/snes/alt/ppu-performance/ppu.cpp b/bsnes/snes/alt/ppu-performance/ppu.cpp index 8b57ed29..4ed933b8 100755 --- a/bsnes/snes/alt/ppu-performance/ppu.cpp +++ b/bsnes/snes/alt/ppu-performance/ppu.cpp @@ -1,4 +1,4 @@ -#include +#include #define PPU_CPP namespace SNES { diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index 8f2f9b0f..7f2b3af9 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index 518e9496..680f1911 100755 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -396,7 +396,7 @@ void Cartridge::xml_parse_supergameboy(xml_element &root) { if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m((Memory&)supergameboy); + Mapping m((Memory&)icd2); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } diff --git a/bsnes/snes/cheat/cheat.cpp b/bsnes/snes/cheat/cheat.cpp index 40fdf7cd..b82a621e 100755 --- a/bsnes/snes/cheat/cheat.cpp +++ b/bsnes/snes/cheat/cheat.cpp @@ -1,4 +1,4 @@ -#include +#include #define CHEAT_CPP namespace SNES { diff --git a/bsnes/snes/chip/bsx/bsx.cpp b/bsnes/snes/chip/bsx/bsx.cpp index 8a083103..a22798f1 100755 --- a/bsnes/snes/chip/bsx/bsx.cpp +++ b/bsnes/snes/chip/bsx/bsx.cpp @@ -1,4 +1,4 @@ -#include +#include #define BSX_CPP namespace SNES { diff --git a/bsnes/snes/chip/chip.hpp b/bsnes/snes/chip/chip.hpp index 17067beb..da46cc39 100755 --- a/bsnes/snes/chip/chip.hpp +++ b/bsnes/snes/chip/chip.hpp @@ -3,21 +3,21 @@ struct Coprocessor : Processor { alwaysinline void synchronize_cpu(); }; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include void Coprocessor::step(unsigned clocks) { clock += clocks * (uint64)cpu.frequency; diff --git a/bsnes/snes/chip/cx4/cx4.cpp b/bsnes/snes/chip/cx4/cx4.cpp index f6362e7c..787378ba 100755 --- a/bsnes/snes/chip/cx4/cx4.cpp +++ b/bsnes/snes/chip/cx4/cx4.cpp @@ -4,7 +4,7 @@ //Used in Rockman X2/X3 (Megaman X2/X3) //Portions (c) anomie, Overload, zsKnight, Nach, byuu -#include +#include #define CX4_CPP namespace SNES { diff --git a/bsnes/snes/chip/icd2/icd2.cpp b/bsnes/snes/chip/icd2/icd2.cpp new file mode 100755 index 00000000..347222d7 --- /dev/null +++ b/bsnes/snes/chip/icd2/icd2.cpp @@ -0,0 +1,70 @@ +#include + +#define ICD2_CPP +namespace SNES { + +#include "interface/interface.cpp" +#include "mmio/mmio.cpp" +ICD2 icd2; + +void ICD2::Enter() { icd2.enter(); } + +void ICD2::enter() { + while(true) { + if(r6003 & 0x80) { + GameBoy::system.run(); + step(GameBoy::system.clocks_executed); + GameBoy::system.clocks_executed = 0; + } else { //DMG halted + step(4); + } + synchronize_cpu(); + } +} + +void ICD2::init() { +} + +void ICD2::enable() { + mmio[0] = memory::mmio.handle(0x2181); + mmio[1] = memory::mmio.handle(0x2182); + mmio[2] = memory::mmio.handle(0x420b); + memory::mmio.map(0x2181, *this); + memory::mmio.map(0x2182, *this); + memory::mmio.map(0x420b, *this); +} + +void ICD2::power() { + reset(); +} + +void ICD2::reset() { + create(ICD2::Enter, cpu.frequency / 5); + + r2181 = 0x00; + r2182 = 0x00; + + r6000 = 0x00; + r6003 = 0x00; + r6004 = 0xff; + r6005 = 0xff; + r6006 = 0xff; + r6007 = 0xff; + for(unsigned n = 0; n < 16; n++) r7000[n] = 0x00; + r7800 = 0x0000; + mlt_req = 0; + + for(unsigned n = 0; n < 320; n++) vram[n] = 0xff; + + packetsize = 0; + joyp_id = 3; + joyp15lock = 0; + joyp14lock = 0; + pulselock = true; + + GameBoy::system.init(this); + GameBoy::cartridge.load(memory::gbrom.data(), memory::gbrom.size()); + GameBoy::system.power(); +} + +} diff --git a/bsnes/snes/chip/icd2/icd2.hpp b/bsnes/snes/chip/icd2/icd2.hpp new file mode 100755 index 00000000..76bbb10f --- /dev/null +++ b/bsnes/snes/chip/icd2/icd2.hpp @@ -0,0 +1,16 @@ +class ICD2 : public GameBoy::Interface, public Coprocessor, public MMIO, public Memory { +public: + static void Enter(); + void enter(); + + void init(); + void enable(); + void power(); + void reset(); + +private: + #include "interface/interface.hpp" + #include "mmio/mmio.hpp" +}; + +extern ICD2 icd2; diff --git a/bsnes/snes/chip/icd2/interface/interface.cpp b/bsnes/snes/chip/icd2/interface/interface.cpp new file mode 100755 index 00000000..f4685d8b --- /dev/null +++ b/bsnes/snes/chip/icd2/interface/interface.cpp @@ -0,0 +1,107 @@ +#ifdef ICD2_CPP + +void ICD2::joyp_write(bool p15, bool p14) { + //joypad handling + if(p15 == 1 && p14 == 1) { + if(joyp15lock == 0 && joyp14lock == 0) { + joyp15lock = 1; + joyp14lock = 1; + joyp_id = (joyp_id + 1) & 3; + } + } + + if(p15 == 0 && p14 == 1) joyp15lock = 0; + if(p15 == 1 && p14 == 0) joyp14lock = 0; + + //packet handling + if(p15 == 0 && p14 == 0) { //pulse + pulselock = false; + packetoffset = 0; + bitoffset = 0; + strobelock = true; + packetlock = false; + return; + } + + if(pulselock) return; + + if(p15 == 1 && p14 == 1) { + strobelock = false; + return; + } + + if(strobelock) { + if(p15 == 1 || p14 == 1) { //malformed packet + packetlock = false; + pulselock = true; + bitoffset = 0; + packetoffset = 0; + } else { + return; + } + } + + //p15:1, p14:0 = 0 + //p15:0, p14:1 = 1 + bool bit = (p15 == 0); + strobelock = true; + + if(packetlock) { + if(p15 == 1 && p14 == 0) { + if((joyp_packet[0] >> 3) == 0x11) { + mlt_req = joyp_packet[1] & 3; + if(mlt_req == 2) mlt_req = 3; + joyp_id = 0; + } + + if(packetsize < 64) packet[packetsize++] = joyp_packet; + packetlock = false; + pulselock = true; + } + return; + } + + bitdata = (bit << 7) | (bitdata >> 1); + if(++bitoffset < 8) return; + + bitoffset = 0; + joyp_packet[packetoffset] = bitdata; + if(++packetoffset < 16) return; + packetlock = true; +} + +void ICD2::video_refresh(const uint8_t *data) { +} + +void ICD2::audio_sample(signed left, signed right) { +} + +void ICD2::input_poll() { +} + +bool ICD2::input_poll(unsigned id) { + GameBoy::cpu.status.mlt_req = joyp_id & mlt_req; + + unsigned data = 0x00; + switch(joyp_id & mlt_req) { + case 0: data = ~r6004; break; + case 1: data = ~r6005; break; + case 2: data = ~r6006; break; + case 3: data = ~r6007; break; + } + + switch(id) { + case GameBoy::Input::Start: return data & 0x80; + case GameBoy::Input::Select: return data & 0x40; + case GameBoy::Input::B: return data & 0x20; + case GameBoy::Input::A: return data & 0x10; + case GameBoy::Input::Down: return data & 0x08; + case GameBoy::Input::Up: return data & 0x04; + case GameBoy::Input::Left: return data & 0x02; + case GameBoy::Input::Right: return data & 0x01; + } + + return 0; +} + +#endif diff --git a/bsnes/snes/chip/icd2/interface/interface.hpp b/bsnes/snes/chip/icd2/interface/interface.hpp new file mode 100755 index 00000000..2227706f --- /dev/null +++ b/bsnes/snes/chip/icd2/interface/interface.hpp @@ -0,0 +1,22 @@ +void joyp_write(bool p15, bool p14); +void video_refresh(const uint8_t *data); +void audio_sample(signed left, signed right); +void input_poll(); +bool input_poll(unsigned id); + +struct Packet { + uint8 data[16]; + uint8& operator[](unsigned addr) { return data[addr & 15]; } +}; +Packet packet[64]; +unsigned packetsize; + +unsigned joyp_id; +bool joyp15lock; +bool joyp14lock; +bool pulselock; +bool strobelock; +bool packetlock; +Packet joyp_packet; +uint8 packetoffset; +uint8 bitdata, bitoffset; diff --git a/bsnes/snes/chip/icd2/mmio/mmio.cpp b/bsnes/snes/chip/icd2/mmio/mmio.cpp new file mode 100755 index 00000000..71d7267c --- /dev/null +++ b/bsnes/snes/chip/icd2/mmio/mmio.cpp @@ -0,0 +1,104 @@ +#ifdef ICD2_CPP + +uint8 ICD2::mmio_read(unsigned addr) { + if((uint16)addr == 0x2181) return mmio[0]->mmio_read(addr); + if((uint16)addr == 0x2182) return mmio[1]->mmio_read(addr); + if((uint16)addr == 0x420b) return mmio[2]->mmio_read(addr); + return 0x00; +} + +void ICD2::mmio_write(unsigned addr, uint8 data) { + if((uint16)addr == 0x420b && data == 0x10) { + unsigned offset = (r2182 << 8) | (r2181 << 0); + r7800 = 0; + unsigned row = 0; + if(offset >= 0x5000 && offset <= 0x6540) row = (offset - 0x5000) / 320; + if(offset >= 0x6800 && offset <= 0x7d40) row = (offset - 0x6800) / 320; + + uint8 *source = GameBoy::lcd.screen + row * 160 * 8; + memset(vram, 0x00, 320); + + for(unsigned y = row * 8; y < row * 8 + 8; y++) { + for(unsigned x = 0; x < 160; x++) { + unsigned pixel = *source++ / 0x55; + pixel ^= 3; + + unsigned addr = (x / 8 * 16) + ((y & 7) * 2); + vram[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7)); + vram[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7)); + } + } + } + + if((uint16)addr == 0x2181) return mmio[0]->mmio_write(addr, r2181 = data); + if((uint16)addr == 0x2182) return mmio[1]->mmio_write(addr, r2182 = data); + if((uint16)addr == 0x420b) return mmio[2]->mmio_write(addr, data); +} + +uint8 ICD2::read(unsigned addr) { + addr &= 0xffff; + + //LY counter + if(addr == 0x6000) { + return GameBoy::lcd.status.ly; + } + + //command ready port + if(addr == 0x6002) { + bool data = packetsize > 0; + if(data) { + for(unsigned i = 0; i < 16; i++) r7000[i] = packet[0][i]; + packetsize--; + for(unsigned i = 0; i < packetsize; i++) packet[i] = packet[i + 1]; + } + return data; + } + + //ICD2 revision + if(addr == 0x600f) { + return 0x21; + } + + //command port + if((addr & 0xfff0) == 0x7000) { + return r7000[addr & 15]; + } + + //VRAM port + if(addr == 0x7800) { + uint8 data = vram[r7800]; + r7800 = (r7800 + 1) % 320; + return data; + } + + return 0x00; +} + +void ICD2::write(unsigned addr, uint8 data) { + addr &= 0xffff; + + //control port + //d7: 0 = halt, 1 = reset + //d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ??? + //d1,d0: 0 = frequency divider (clock rate adjust) + if(addr == 0x6003) { + if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) { + reset(); + } + switch(data & 3) { + case 0: frequency = cpu.frequency / 4; break; //fast (glitchy, even on real hardware) + case 1: frequency = cpu.frequency / 5; break; //normal + case 2: frequency = cpu.frequency / 7; break; //slow + case 3: frequency = cpu.frequency / 9; break; //very slow + } + r6003 = data; + return; + } + + if(addr == 0x6004) { r6004 = data; return; } //joypad 1 + if(addr == 0x6005) { r6005 = data; return; } //joypad 2 + if(addr == 0x6006) { r6006 = data; return; } //joypad 3 + if(addr == 0x6007) { r6007 = data; return; } //joypad 4 +} + +#endif diff --git a/bsnes/snes/chip/icd2/mmio/mmio.hpp b/bsnes/snes/chip/icd2/mmio/mmio.hpp new file mode 100755 index 00000000..69a4b7f9 --- /dev/null +++ b/bsnes/snes/chip/icd2/mmio/mmio.hpp @@ -0,0 +1,19 @@ +uint8 r2181; +uint8 r2182; +MMIO *mmio[3]; +uint8 mmio_read(unsigned addr); +void mmio_write(unsigned addr, uint8 data); + +uint8 r6000; +uint8 r6003; +uint8 r6004; +uint8 r6005; +uint8 r6006; +uint8 r6007; +uint8 r7000[16]; +unsigned r7800; +uint8 mlt_req; +uint8 read(unsigned addr); +void write(unsigned addr, uint8 data); + +uint8 vram[320]; diff --git a/bsnes/snes/chip/msu1/msu1.cpp b/bsnes/snes/chip/msu1/msu1.cpp index fa58d457..49e3930b 100755 --- a/bsnes/snes/chip/msu1/msu1.cpp +++ b/bsnes/snes/chip/msu1/msu1.cpp @@ -1,4 +1,4 @@ -#include +#include #define MSU1_CPP namespace SNES { diff --git a/bsnes/snes/chip/obc1/obc1.cpp b/bsnes/snes/chip/obc1/obc1.cpp index 4b79a4c2..52770941 100755 --- a/bsnes/snes/chip/obc1/obc1.cpp +++ b/bsnes/snes/chip/obc1/obc1.cpp @@ -1,4 +1,4 @@ -#include +#include #define OBC1_CPP namespace SNES { diff --git a/bsnes/snes/chip/sa1/sa1.cpp b/bsnes/snes/chip/sa1/sa1.cpp index 5c24a1f7..7daeb173 100755 --- a/bsnes/snes/chip/sa1/sa1.cpp +++ b/bsnes/snes/chip/sa1/sa1.cpp @@ -1,4 +1,4 @@ -#include +#include #define SA1_CPP namespace SNES { diff --git a/bsnes/snes/chip/sdd1/sdd1.cpp b/bsnes/snes/chip/sdd1/sdd1.cpp index 83119f14..e7a98103 100755 --- a/bsnes/snes/chip/sdd1/sdd1.cpp +++ b/bsnes/snes/chip/sdd1/sdd1.cpp @@ -1,4 +1,4 @@ -#include +#include #define SDD1_CPP namespace SNES { diff --git a/bsnes/snes/chip/serial/serial.cpp b/bsnes/snes/chip/serial/serial.cpp index cc50fcca..4384d782 100755 --- a/bsnes/snes/chip/serial/serial.cpp +++ b/bsnes/snes/chip/serial/serial.cpp @@ -1,4 +1,4 @@ -#include +#include #define SERIAL_CPP namespace SNES { diff --git a/bsnes/snes/chip/spc7110/spc7110.cpp b/bsnes/snes/chip/spc7110/spc7110.cpp index 3559a631..172731e2 100755 --- a/bsnes/snes/chip/spc7110/spc7110.cpp +++ b/bsnes/snes/chip/spc7110/spc7110.cpp @@ -1,4 +1,4 @@ -#include +#include #define SPC7110_CPP namespace SNES { diff --git a/bsnes/snes/chip/srtc/srtc.cpp b/bsnes/snes/chip/srtc/srtc.cpp index 965a0ef0..8c8e08e1 100755 --- a/bsnes/snes/chip/srtc/srtc.cpp +++ b/bsnes/snes/chip/srtc/srtc.cpp @@ -1,4 +1,4 @@ -#include +#include #define SRTC_CPP namespace SNES { diff --git a/bsnes/snes/chip/st0010/st0010.cpp b/bsnes/snes/chip/st0010/st0010.cpp index 295d0f5a..5331af65 100755 --- a/bsnes/snes/chip/st0010/st0010.cpp +++ b/bsnes/snes/chip/st0010/st0010.cpp @@ -1,4 +1,4 @@ -#include +#include #define ST0010_CPP namespace SNES { diff --git a/bsnes/snes/chip/st0011/st0011.cpp b/bsnes/snes/chip/st0011/st0011.cpp index fe8e9c23..646e3424 100755 --- a/bsnes/snes/chip/st0011/st0011.cpp +++ b/bsnes/snes/chip/st0011/st0011.cpp @@ -1,4 +1,4 @@ -#include +#include #define ST0011_CPP namespace SNES { diff --git a/bsnes/snes/chip/st0018/st0018.cpp b/bsnes/snes/chip/st0018/st0018.cpp index 03ef4d0f..367f09ab 100755 --- a/bsnes/snes/chip/st0018/st0018.cpp +++ b/bsnes/snes/chip/st0018/st0018.cpp @@ -1,4 +1,4 @@ -#include +#include #define ST0018_CPP namespace SNES { diff --git a/bsnes/snes/chip/superfx/superfx.cpp b/bsnes/snes/chip/superfx/superfx.cpp index 89eaf18b..011b80bb 100755 --- a/bsnes/snes/chip/superfx/superfx.cpp +++ b/bsnes/snes/chip/superfx/superfx.cpp @@ -1,4 +1,4 @@ -#include +#include #define SUPERFX_CPP namespace SNES { diff --git a/bsnes/snes/chip/supergameboy/serialization.cpp b/bsnes/snes/chip/supergameboy/serialization.cpp deleted file mode 100755 index 727bdff4..00000000 --- a/bsnes/snes/chip/supergameboy/serialization.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifdef SUPERGAMEBOY_CPP - -void SuperGameBoy::serialize(serializer &s) { - Processor::serialize(s); - s.integer(row); - if(sgb_serialize) sgb_serialize(s); -} - -#endif diff --git a/bsnes/snes/chip/supergameboy/supergameboy.cpp b/bsnes/snes/chip/supergameboy/supergameboy.cpp deleted file mode 100755 index 562cd9be..00000000 --- a/bsnes/snes/chip/supergameboy/supergameboy.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include - -#define SUPERGAMEBOY_CPP -namespace SNES { - -SuperGameBoy supergameboy; - -#include "serialization.cpp" - -void SuperGameBoy::Enter() { supergameboy.enter(); } - -void SuperGameBoy::enter() { - if(!sgb_run) while(true) { - if(scheduler.sync == Scheduler::SynchronizeMode::All) { - scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); - } - - audio.coprocessor_sample(0, 0); - step(1); - synchronize_cpu(); - } - - while(true) { - if(scheduler.sync == Scheduler::SynchronizeMode::All) { - scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); - } - - unsigned samples = sgb_run(samplebuffer, 16); - for(unsigned i = 0; i < samples; i++) { - int16 left = samplebuffer[i] >> 0; - int16 right = samplebuffer[i] >> 16; - - //SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects - audio.coprocessor_sample(left / 3, right / 3); - } - - step(samples); - synchronize_cpu(); - } -} - -void SuperGameBoy::save() { - if(sgb_save) sgb_save(); -} - -uint8 SuperGameBoy::mmio_read(unsigned addr) { - addr &= 0xffff; - - if(addr == 0x2181) return mmio[0]->mmio_read(addr); - if(addr == 0x2182) return mmio[1]->mmio_read(addr); - if(addr == 0x420b) return mmio[2]->mmio_read(addr); - - return 0x00; -} - -void SuperGameBoy::mmio_write(unsigned addr, uint8 data) { - addr &= 0xffff; - - if(addr == 0x2181) { - row = (row & 0xff00) | (data << 0); - mmio[0]->mmio_write(addr, data); - } - - if(addr == 0x2182) { - row = (row & 0x00ff) | (data << 8); - mmio[1]->mmio_write(addr, data); - } - - if(addr == 0x420b) { - if(data == 0x10 && sgb_row) { - if(row >= 0x5000 && row <= 0x6540) sgb_row((row - 0x5000) / 320); - if(row >= 0x6800 && row <= 0x7d40) sgb_row((row - 0x6800) / 320); - } - mmio[2]->mmio_write(addr, data); - } -} - -uint8 SuperGameBoy::read(unsigned addr) { - if(sgb_read) return sgb_read(addr); - return 0x00; -} - -void SuperGameBoy::write(unsigned addr, uint8 data) { - if(sgb_write) sgb_write(addr, data); -} - -void SuperGameBoy::init() { - if(open("supergameboy")) { - sgb_rom = sym("sgb_rom"); - sgb_ram = sym("sgb_ram"); - sgb_rtc = sym("sgb_rtc"); - sgb_init = sym("sgb_init"); - sgb_term = sym("sgb_term"); - sgb_power = sym("sgb_power"); - sgb_reset = sym("sgb_reset"); - sgb_row = sym("sgb_row"); - sgb_read = sym("sgb_read"); - sgb_write = sym("sgb_write"); - sgb_run = sym("sgb_run"); - sgb_save = sym("sgb_save"); - sgb_serialize = sym("sgb_serialize"); - } -} - -void SuperGameBoy::enable() { - mmio[0] = memory::mmio.handle(0x2181); - mmio[1] = memory::mmio.handle(0x2182); - mmio[2] = memory::mmio.handle(0x420b); - memory::mmio.map(0x2181, *this); - memory::mmio.map(0x2182, *this); - memory::mmio.map(0x420b, *this); -} - -void SuperGameBoy::power() { - unsigned frequency = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? system.cpu_frequency() / 10 : 2097152); - create(SuperGameBoy::Enter, frequency); - - audio.coprocessor_enable(true); - audio.coprocessor_frequency(cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? 2147727.0 : 2097152.0); - - sgb_rom(memory::gbrom.data(), memory::gbrom.size() == -1U ? 0 : memory::gbrom.size()); - sgb_ram(memory::gbram.data(), memory::gbram.size() == -1U ? 0 : memory::gbram.size()); - sgb_rtc(memory::gbrtc.data(), memory::gbrtc.size() == -1U ? 0 : memory::gbrtc.size()); - - bool version = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1) ? 0 : 1; - if(sgb_init) sgb_init(version); - if(sgb_power) sgb_power(); -} - -void SuperGameBoy::reset() { - unsigned frequency = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? system.cpu_frequency() / 10 : 2097152); - create(SuperGameBoy::Enter, frequency); - - if(sgb_reset) sgb_reset(); -} - -void SuperGameBoy::unload() { - if(sgb_term) sgb_term(); -} - -} diff --git a/bsnes/snes/chip/supergameboy/supergameboy.hpp b/bsnes/snes/chip/supergameboy/supergameboy.hpp deleted file mode 100755 index bf392b11..00000000 --- a/bsnes/snes/chip/supergameboy/supergameboy.hpp +++ /dev/null @@ -1,43 +0,0 @@ -class SuperGameBoy : public Coprocessor, public MMIO, public Memory, public library { -public: - static void Enter(); - void enter(); - void save(); - - MMIO *mmio[3]; - uint8 mmio_read(unsigned addr); - void mmio_write(unsigned addr, uint8 data); - - uint8 read(unsigned addr); - void write(unsigned addr, uint8 data); - - void init(); - void enable(); - void power(); - void reset(); - void unload(); - - void serialize(serializer&); - -private: - uint32_t samplebuffer[4096]; - unsigned row; - - function sgb_rom; - function sgb_ram; - function sgb_rtc; - function sgb_init; - function sgb_term; - function sgb_power; - function sgb_reset; - function sgb_row; - function sgb_read; - function sgb_write; - function sgb_run; - function sgb_save; - function sgb_serialize; - - friend class Cartridge; -}; - -extern SuperGameBoy supergameboy; diff --git a/bsnes/snes/chip/upd77c25/upd77c25.cpp b/bsnes/snes/chip/upd77c25/upd77c25.cpp index 99a3d540..8323eff9 100755 --- a/bsnes/snes/chip/upd77c25/upd77c25.cpp +++ b/bsnes/snes/chip/upd77c25/upd77c25.cpp @@ -7,7 +7,7 @@ //* interrupts //* DMA -#include +#include #define UPD77C25_CPP namespace SNES { diff --git a/bsnes/snes/cpu/core/core.cpp b/bsnes/snes/cpu/core/core.cpp index aae4ba67..bce1ca29 100755 --- a/bsnes/snes/cpu/core/core.cpp +++ b/bsnes/snes/cpu/core/core.cpp @@ -1,4 +1,4 @@ -#include +#include #define CPUCORE_CPP namespace SNES { diff --git a/bsnes/snes/cpu/cpu.cpp b/bsnes/snes/cpu/cpu.cpp index 4c194b27..8ba06ec7 100755 --- a/bsnes/snes/cpu/cpu.cpp +++ b/bsnes/snes/cpu/cpu.cpp @@ -1,4 +1,4 @@ -#include +#include #define CPU_CPP namespace SNES { diff --git a/bsnes/snes/dsp/dsp.cpp b/bsnes/snes/dsp/dsp.cpp index 079b76d5..4811269b 100755 --- a/bsnes/snes/dsp/dsp.cpp +++ b/bsnes/snes/dsp/dsp.cpp @@ -1,4 +1,4 @@ -#include +#include #define DSP_CPP namespace SNES { diff --git a/bsnes/snes/memory/memory.cpp b/bsnes/snes/memory/memory.cpp index 63385c75..4a627486 100755 --- a/bsnes/snes/memory/memory.cpp +++ b/bsnes/snes/memory/memory.cpp @@ -1,4 +1,4 @@ -#include +#include #define MEMORY_CPP namespace SNES { diff --git a/bsnes/snes/ppu/ppu.cpp b/bsnes/snes/ppu/ppu.cpp index 7d8d977e..1d66a770 100755 --- a/bsnes/snes/ppu/ppu.cpp +++ b/bsnes/snes/ppu/ppu.cpp @@ -1,4 +1,4 @@ -#include +#include #define PPU_CPP namespace SNES { diff --git a/bsnes/snes/profile-accuracy.hpp b/bsnes/snes/profile-accuracy.hpp index 006968cb..7b6dded8 100755 --- a/bsnes/snes/profile-accuracy.hpp +++ b/bsnes/snes/profile-accuracy.hpp @@ -2,7 +2,7 @@ namespace Info { static const char Profile[] = "Accuracy"; } -#include -#include -#include -#include +#include +#include +#include +#include diff --git a/bsnes/snes/profile-compatibility.hpp b/bsnes/snes/profile-compatibility.hpp index b3e3a0eb..bbf3582d 100755 --- a/bsnes/snes/profile-compatibility.hpp +++ b/bsnes/snes/profile-compatibility.hpp @@ -2,7 +2,7 @@ namespace Info { static const char Profile[] = "Compatibility"; } -#include -#include -#include -#include +#include +#include +#include +#include diff --git a/bsnes/snes/profile-performance.hpp b/bsnes/snes/profile-performance.hpp index b21fbbb1..8562e47b 100755 --- a/bsnes/snes/profile-performance.hpp +++ b/bsnes/snes/profile-performance.hpp @@ -2,7 +2,7 @@ namespace Info { static const char Profile[] = "Performance"; } -#include -#include -#include -#include +#include +#include +#include +#include diff --git a/bsnes/snes/smp/core/core.cpp b/bsnes/snes/smp/core/core.cpp index 88243dad..51fa453e 100755 --- a/bsnes/snes/smp/core/core.cpp +++ b/bsnes/snes/smp/core/core.cpp @@ -1,4 +1,4 @@ -#include +#include #define SMPCORE_CPP namespace SNES { diff --git a/bsnes/snes/smp/smp.cpp b/bsnes/snes/smp/smp.cpp index 454d6bf5..878ca0de 100755 --- a/bsnes/snes/smp/smp.cpp +++ b/bsnes/snes/smp/smp.cpp @@ -1,4 +1,4 @@ -#include +#include #define SMP_CPP namespace SNES { diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 1da20b2f..7d627a6a 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "073.01"; + static const char Version[] = "073.02"; static const unsigned SerializerVersion = 16; } } @@ -32,6 +32,8 @@ namespace SNES { #include using namespace nall; +#include + #ifdef DEBUGGER #define debugvirtual virtual #else @@ -109,10 +111,10 @@ namespace SNES { virtual bool property(unsigned id, string &name, string &value) = 0; }; - #include - #include - #include - #include + #include + #include + #include + #include #if defined(PROFILE_ACCURACY) #include "profile-accuracy.hpp" @@ -122,14 +124,14 @@ namespace SNES { #include "profile-performance.hpp" #endif - #include - #include - #include - #include + #include + #include + #include + #include - #include - #include - #include + #include + #include + #include } namespace nall { diff --git a/bsnes/snes/system/serialization.cpp b/bsnes/snes/system/serialization.cpp index 1b87ce51..5671406b 100755 --- a/bsnes/snes/system/serialization.cpp +++ b/bsnes/snes/system/serialization.cpp @@ -57,7 +57,7 @@ void System::serialize_all(serializer &s) { ppu.serialize(s); dsp.serialize(s); - if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.serialize(s); +//if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.serialize(s); if(cartridge.has_superfx()) superfx.serialize(s); if(cartridge.has_sa1()) sa1.serialize(s); if(cartridge.has_upd77c25()) upd77c25.serialize(s); diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index bebd7258..4395d199 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -1,17 +1,17 @@ -#include +#include #define SYSTEM_CPP namespace SNES { System system; -#include -#include -#include +#include +#include +#include -#include