mirror of https://github.com/bsnes-emu/bsnes.git
Update to v073r02 release.
byuu says: Changelog: - removed bsnes/supergameboy (libgameboy -> libgambatte binding) - added direct ICD2-R coprocessor emulation - linked in bgameboy to the ICD2-R module - Makefile removes -Isnes, all files adjusted from <name.hpp> to <snes/name.hpp> [relic from asnes split] You can now play Super Game Boy games with the core bsnes library.
This commit is contained in:
commit
3f960374ad
|
@ -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:;
|
||||
|
|
|
@ -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/)
|
|
@ -0,0 +1,168 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#include <nall/crc32.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
struct Cartridge : property<Cartridge> {
|
||||
#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<bool> 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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
struct MBC0 : MMIO {
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc0;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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<unsigned x, unsigned y> void CPU::op_ld_r_r() {
|
||||
r[x] = r[y];
|
||||
}
|
||||
|
||||
template<unsigned x> void CPU::op_ld_r_n() {
|
||||
r[x] = op_read(r[PC]++);
|
||||
}
|
||||
|
||||
template<unsigned x> void CPU::op_ld_r_hl() {
|
||||
r[x] = op_read(r[HL]);
|
||||
}
|
||||
|
||||
template<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> void CPU::op_push_rr() {
|
||||
op_write(--r[SP], r[x] >> 8);
|
||||
op_write(--r[SP], r[x] >> 0);
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> void CPU::op_inc_rr() {
|
||||
op_io();
|
||||
r[x]++;
|
||||
}
|
||||
|
||||
template<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned x> 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<unsigned b, unsigned x> void CPU::op_bit_n_r() {
|
||||
r.f.z = (r[x] & (1 << b)) == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = 1;
|
||||
}
|
||||
|
||||
template<unsigned b> 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<unsigned b, unsigned x> void CPU::op_set_n_r() {
|
||||
r[x] |= 1 << b;
|
||||
}
|
||||
|
||||
template<unsigned b> void CPU::op_set_n_hl() {
|
||||
uint8 n = op_read(r[HL]);
|
||||
n |= 1 << b;
|
||||
op_write(r[HL], n);
|
||||
}
|
||||
|
||||
template<unsigned b, unsigned x> void CPU::op_res_n_r() {
|
||||
r[x] &= ~(1 << b);
|
||||
}
|
||||
|
||||
template<unsigned b> 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<unsigned x, bool y> 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<unsigned x, bool y> 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<unsigned x, bool y> 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<unsigned x, bool y> 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<unsigned n> 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
|
|
@ -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<unsigned x, unsigned y> void op_ld_r_r();
|
||||
template<unsigned x> void op_ld_r_n();
|
||||
template<unsigned x> void op_ld_r_hl();
|
||||
template<unsigned x> void op_ld_hl_r();
|
||||
void op_ld_hl_n();
|
||||
template<unsigned x> void op_ld_a_rr();
|
||||
void op_ld_a_nn();
|
||||
template<unsigned x> 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<unsigned x> void op_ld_rr_nn();
|
||||
void op_ld_nn_sp();
|
||||
void op_ld_sp_hl();
|
||||
template<unsigned x> void op_push_rr();
|
||||
template<unsigned x> void op_pop_rr();
|
||||
|
||||
//8-bit arithmetic commands
|
||||
void opi_add_a(uint8 x);
|
||||
template<unsigned x> void op_add_a_r();
|
||||
void op_add_a_n();
|
||||
void op_add_a_hl();
|
||||
|
||||
void opi_adc_a(uint8 x);
|
||||
template<unsigned x> void op_adc_a_r();
|
||||
void op_adc_a_n();
|
||||
void op_adc_a_hl();
|
||||
|
||||
void opi_sub_a(uint8 x);
|
||||
template<unsigned x> void op_sub_a_r();
|
||||
void op_sub_a_n();
|
||||
void op_sub_a_hl();
|
||||
|
||||
void opi_sbc_a(uint8 x);
|
||||
template<unsigned x> void op_sbc_a_r();
|
||||
void op_sbc_a_n();
|
||||
void op_sbc_a_hl();
|
||||
|
||||
void opi_and_a(uint8 x);
|
||||
template<unsigned x> void op_and_a_r();
|
||||
void op_and_a_n();
|
||||
void op_and_a_hl();
|
||||
|
||||
void opi_xor_a(uint8 x);
|
||||
template<unsigned x> void op_xor_a_r();
|
||||
void op_xor_a_n();
|
||||
void op_xor_a_hl();
|
||||
|
||||
void opi_or_a(uint8 x);
|
||||
template<unsigned x> void op_or_a_r();
|
||||
void op_or_a_n();
|
||||
void op_or_a_hl();
|
||||
|
||||
void opi_cp_a(uint8 x);
|
||||
template<unsigned x> void op_cp_a_r();
|
||||
void op_cp_a_n();
|
||||
void op_cp_a_hl();
|
||||
|
||||
template<unsigned x> void op_inc_r();
|
||||
void op_inc_hl();
|
||||
template<unsigned x> void op_dec_r();
|
||||
void op_dec_hl();
|
||||
void op_daa();
|
||||
void op_cpl();
|
||||
|
||||
//16-bit arithmetic commands
|
||||
template<unsigned x> void op_add_hl_rr();
|
||||
template<unsigned x> void op_inc_rr();
|
||||
template<unsigned x> 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<unsigned x> void op_rlc_r();
|
||||
void op_rlc_hl();
|
||||
template<unsigned x> void op_rl_r();
|
||||
void op_rl_hl();
|
||||
template<unsigned x> void op_rrc_r();
|
||||
void op_rrc_hl();
|
||||
template<unsigned x> void op_rr_r();
|
||||
void op_rr_hl();
|
||||
template<unsigned x> void op_sla_r();
|
||||
void op_sla_hl();
|
||||
template<unsigned x> void op_swap_r();
|
||||
void op_swap_hl();
|
||||
template<unsigned x> void op_sra_r();
|
||||
void op_sra_hl();
|
||||
template<unsigned x> void op_srl_r();
|
||||
void op_srl_hl();
|
||||
|
||||
//single-bit commands
|
||||
template<unsigned b, unsigned x> void op_bit_n_r();
|
||||
template<unsigned b> void op_bit_n_hl();
|
||||
template<unsigned b, unsigned x> void op_set_n_r();
|
||||
template<unsigned b> void op_set_n_hl();
|
||||
template<unsigned b, unsigned x> void op_res_n_r();
|
||||
template<unsigned b> 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<unsigned x, bool y> void op_jp_f_nn();
|
||||
void op_jr_n();
|
||||
template<unsigned x, bool y> void op_jr_f_n();
|
||||
void op_call_nn();
|
||||
template<unsigned x, bool y> void op_call_f_nn();
|
||||
void op_ret();
|
||||
template<unsigned x, bool y> void op_ret_f();
|
||||
void op_reti();
|
||||
template<unsigned n> void op_rst_n();
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble(uint16 pc);
|
||||
string disassemble_opcode(uint16 pc);
|
||||
string disassemble_opcode_cb(uint16 pc);
|
|
@ -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
|
|
@ -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;
|
|
@ -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<BC>;
|
||||
opcode_table[0x02] = &CPU::op_ld_rr_a<BC>;
|
||||
opcode_table[0x03] = &CPU::op_inc_rr<BC>;
|
||||
opcode_table[0x04] = &CPU::op_inc_r<B>;
|
||||
opcode_table[0x05] = &CPU::op_dec_r<B>;
|
||||
opcode_table[0x06] = &CPU::op_ld_r_n<B>;
|
||||
opcode_table[0x07] = &CPU::op_rlca;
|
||||
opcode_table[0x08] = &CPU::op_ld_nn_sp;
|
||||
opcode_table[0x09] = &CPU::op_add_hl_rr<BC>;
|
||||
opcode_table[0x0a] = &CPU::op_ld_a_rr<BC>;
|
||||
opcode_table[0x0b] = &CPU::op_dec_rr<BC>;
|
||||
opcode_table[0x0c] = &CPU::op_inc_r<C>;
|
||||
opcode_table[0x0d] = &CPU::op_dec_r<C>;
|
||||
opcode_table[0x0e] = &CPU::op_ld_r_n<C>;
|
||||
opcode_table[0x0f] = &CPU::op_rrca;
|
||||
opcode_table[0x10] = &CPU::op_stop;
|
||||
opcode_table[0x11] = &CPU::op_ld_rr_nn<DE>;
|
||||
opcode_table[0x12] = &CPU::op_ld_rr_a<DE>;
|
||||
opcode_table[0x13] = &CPU::op_inc_rr<DE>;
|
||||
opcode_table[0x14] = &CPU::op_inc_r<D>;
|
||||
opcode_table[0x15] = &CPU::op_dec_r<D>;
|
||||
opcode_table[0x16] = &CPU::op_ld_r_n<D>;
|
||||
opcode_table[0x17] = &CPU::op_rla;
|
||||
opcode_table[0x18] = &CPU::op_jr_n;
|
||||
opcode_table[0x19] = &CPU::op_add_hl_rr<DE>;
|
||||
opcode_table[0x1a] = &CPU::op_ld_a_rr<DE>;
|
||||
opcode_table[0x1b] = &CPU::op_dec_rr<DE>;
|
||||
opcode_table[0x1c] = &CPU::op_inc_r<E>;
|
||||
opcode_table[0x1d] = &CPU::op_dec_r<E>;
|
||||
opcode_table[0x1e] = &CPU::op_ld_r_n<E>;
|
||||
opcode_table[0x1f] = &CPU::op_rra;
|
||||
opcode_table[0x20] = &CPU::op_jr_f_n<ZF, 0>;
|
||||
opcode_table[0x21] = &CPU::op_ld_rr_nn<HL>;
|
||||
opcode_table[0x22] = &CPU::op_ldi_hl_a;
|
||||
opcode_table[0x23] = &CPU::op_inc_rr<HL>;
|
||||
opcode_table[0x24] = &CPU::op_inc_r<H>;
|
||||
opcode_table[0x25] = &CPU::op_dec_r<H>;
|
||||
opcode_table[0x26] = &CPU::op_ld_r_n<H>;
|
||||
opcode_table[0x27] = &CPU::op_daa;
|
||||
opcode_table[0x28] = &CPU::op_jr_f_n<ZF, 1>;
|
||||
opcode_table[0x29] = &CPU::op_add_hl_rr<HL>;
|
||||
opcode_table[0x2a] = &CPU::op_ldi_a_hl;
|
||||
opcode_table[0x2b] = &CPU::op_dec_rr<HL>;
|
||||
opcode_table[0x2c] = &CPU::op_inc_r<L>;
|
||||
opcode_table[0x2d] = &CPU::op_dec_r<L>;
|
||||
opcode_table[0x2e] = &CPU::op_ld_r_n<L>;
|
||||
opcode_table[0x2f] = &CPU::op_cpl;
|
||||
opcode_table[0x30] = &CPU::op_jr_f_n<CF, 0>;
|
||||
opcode_table[0x31] = &CPU::op_ld_rr_nn<SP>;
|
||||
opcode_table[0x32] = &CPU::op_ldd_hl_a;
|
||||
opcode_table[0x33] = &CPU::op_inc_rr<SP>;
|
||||
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<CF, 1>;
|
||||
opcode_table[0x39] = &CPU::op_add_hl_rr<SP>;
|
||||
opcode_table[0x3a] = &CPU::op_ldd_a_hl;
|
||||
opcode_table[0x3b] = &CPU::op_dec_rr<SP>;
|
||||
opcode_table[0x3c] = &CPU::op_inc_r<A>;
|
||||
opcode_table[0x3d] = &CPU::op_dec_r<A>;
|
||||
opcode_table[0x3e] = &CPU::op_ld_r_n<A>;
|
||||
opcode_table[0x3f] = &CPU::op_ccf;
|
||||
opcode_table[0x40] = &CPU::op_ld_r_r<B, B>;
|
||||
opcode_table[0x41] = &CPU::op_ld_r_r<B, C>;
|
||||
opcode_table[0x42] = &CPU::op_ld_r_r<B, D>;
|
||||
opcode_table[0x43] = &CPU::op_ld_r_r<B, E>;
|
||||
opcode_table[0x44] = &CPU::op_ld_r_r<B, H>;
|
||||
opcode_table[0x45] = &CPU::op_ld_r_r<B, L>;
|
||||
opcode_table[0x46] = &CPU::op_ld_r_hl<B>;
|
||||
opcode_table[0x47] = &CPU::op_ld_r_r<B, A>;
|
||||
opcode_table[0x48] = &CPU::op_ld_r_r<C, B>;
|
||||
opcode_table[0x49] = &CPU::op_ld_r_r<C, C>;
|
||||
opcode_table[0x4a] = &CPU::op_ld_r_r<C, D>;
|
||||
opcode_table[0x4b] = &CPU::op_ld_r_r<C, E>;
|
||||
opcode_table[0x4c] = &CPU::op_ld_r_r<C, H>;
|
||||
opcode_table[0x4d] = &CPU::op_ld_r_r<C, L>;
|
||||
opcode_table[0x4e] = &CPU::op_ld_r_hl<C>;
|
||||
opcode_table[0x4f] = &CPU::op_ld_r_r<C, A>;
|
||||
opcode_table[0x50] = &CPU::op_ld_r_r<D, B>;
|
||||
opcode_table[0x51] = &CPU::op_ld_r_r<D, C>;
|
||||
opcode_table[0x52] = &CPU::op_ld_r_r<D, D>;
|
||||
opcode_table[0x53] = &CPU::op_ld_r_r<D, E>;
|
||||
opcode_table[0x54] = &CPU::op_ld_r_r<D, H>;
|
||||
opcode_table[0x55] = &CPU::op_ld_r_r<D, L>;
|
||||
opcode_table[0x56] = &CPU::op_ld_r_hl<D>;
|
||||
opcode_table[0x57] = &CPU::op_ld_r_r<D, A>;
|
||||
opcode_table[0x58] = &CPU::op_ld_r_r<E, B>;
|
||||
opcode_table[0x59] = &CPU::op_ld_r_r<E, C>;
|
||||
opcode_table[0x5a] = &CPU::op_ld_r_r<E, D>;
|
||||
opcode_table[0x5b] = &CPU::op_ld_r_r<E, E>;
|
||||
opcode_table[0x5c] = &CPU::op_ld_r_r<E, H>;
|
||||
opcode_table[0x5d] = &CPU::op_ld_r_r<E, L>;
|
||||
opcode_table[0x5e] = &CPU::op_ld_r_hl<E>;
|
||||
opcode_table[0x5f] = &CPU::op_ld_r_r<E, A>;
|
||||
opcode_table[0x60] = &CPU::op_ld_r_r<H, B>;
|
||||
opcode_table[0x61] = &CPU::op_ld_r_r<H, C>;
|
||||
opcode_table[0x62] = &CPU::op_ld_r_r<H, D>;
|
||||
opcode_table[0x63] = &CPU::op_ld_r_r<H, E>;
|
||||
opcode_table[0x64] = &CPU::op_ld_r_r<H, H>;
|
||||
opcode_table[0x65] = &CPU::op_ld_r_r<H, L>;
|
||||
opcode_table[0x66] = &CPU::op_ld_r_hl<H>;
|
||||
opcode_table[0x67] = &CPU::op_ld_r_r<H, A>;
|
||||
opcode_table[0x68] = &CPU::op_ld_r_r<L, B>;
|
||||
opcode_table[0x69] = &CPU::op_ld_r_r<L, C>;
|
||||
opcode_table[0x6a] = &CPU::op_ld_r_r<L, D>;
|
||||
opcode_table[0x6b] = &CPU::op_ld_r_r<L, E>;
|
||||
opcode_table[0x6c] = &CPU::op_ld_r_r<L, H>;
|
||||
opcode_table[0x6d] = &CPU::op_ld_r_r<L, L>;
|
||||
opcode_table[0x6e] = &CPU::op_ld_r_hl<L>;
|
||||
opcode_table[0x6f] = &CPU::op_ld_r_r<L, A>;
|
||||
opcode_table[0x70] = &CPU::op_ld_hl_r<B>;
|
||||
opcode_table[0x71] = &CPU::op_ld_hl_r<C>;
|
||||
opcode_table[0x72] = &CPU::op_ld_hl_r<D>;
|
||||
opcode_table[0x73] = &CPU::op_ld_hl_r<E>;
|
||||
opcode_table[0x74] = &CPU::op_ld_hl_r<H>;
|
||||
opcode_table[0x75] = &CPU::op_ld_hl_r<L>;
|
||||
opcode_table[0x76] = &CPU::op_halt;
|
||||
opcode_table[0x77] = &CPU::op_ld_hl_r<A>;
|
||||
opcode_table[0x78] = &CPU::op_ld_r_r<A, B>;
|
||||
opcode_table[0x79] = &CPU::op_ld_r_r<A, C>;
|
||||
opcode_table[0x7a] = &CPU::op_ld_r_r<A, D>;
|
||||
opcode_table[0x7b] = &CPU::op_ld_r_r<A, E>;
|
||||
opcode_table[0x7c] = &CPU::op_ld_r_r<A, H>;
|
||||
opcode_table[0x7d] = &CPU::op_ld_r_r<A, L>;
|
||||
opcode_table[0x7e] = &CPU::op_ld_r_hl<A>;
|
||||
opcode_table[0x7f] = &CPU::op_ld_r_r<A, A>;
|
||||
opcode_table[0x80] = &CPU::op_add_a_r<B>;
|
||||
opcode_table[0x81] = &CPU::op_add_a_r<C>;
|
||||
opcode_table[0x82] = &CPU::op_add_a_r<D>;
|
||||
opcode_table[0x83] = &CPU::op_add_a_r<E>;
|
||||
opcode_table[0x84] = &CPU::op_add_a_r<H>;
|
||||
opcode_table[0x85] = &CPU::op_add_a_r<L>;
|
||||
opcode_table[0x86] = &CPU::op_add_a_hl;
|
||||
opcode_table[0x87] = &CPU::op_add_a_r<A>;
|
||||
opcode_table[0x88] = &CPU::op_adc_a_r<B>;
|
||||
opcode_table[0x89] = &CPU::op_adc_a_r<C>;
|
||||
opcode_table[0x8a] = &CPU::op_adc_a_r<D>;
|
||||
opcode_table[0x8b] = &CPU::op_adc_a_r<E>;
|
||||
opcode_table[0x8c] = &CPU::op_adc_a_r<H>;
|
||||
opcode_table[0x8d] = &CPU::op_adc_a_r<L>;
|
||||
opcode_table[0x8e] = &CPU::op_adc_a_hl;
|
||||
opcode_table[0x8f] = &CPU::op_adc_a_r<A>;
|
||||
opcode_table[0x90] = &CPU::op_sub_a_r<B>;
|
||||
opcode_table[0x91] = &CPU::op_sub_a_r<C>;
|
||||
opcode_table[0x92] = &CPU::op_sub_a_r<D>;
|
||||
opcode_table[0x93] = &CPU::op_sub_a_r<E>;
|
||||
opcode_table[0x94] = &CPU::op_sub_a_r<H>;
|
||||
opcode_table[0x95] = &CPU::op_sub_a_r<L>;
|
||||
opcode_table[0x96] = &CPU::op_sub_a_hl;
|
||||
opcode_table[0x97] = &CPU::op_sub_a_r<A>;
|
||||
opcode_table[0x98] = &CPU::op_sbc_a_r<B>;
|
||||
opcode_table[0x99] = &CPU::op_sbc_a_r<C>;
|
||||
opcode_table[0x9a] = &CPU::op_sbc_a_r<D>;
|
||||
opcode_table[0x9b] = &CPU::op_sbc_a_r<E>;
|
||||
opcode_table[0x9c] = &CPU::op_sbc_a_r<H>;
|
||||
opcode_table[0x9d] = &CPU::op_sbc_a_r<L>;
|
||||
opcode_table[0x9e] = &CPU::op_sbc_a_hl;
|
||||
opcode_table[0x9f] = &CPU::op_sbc_a_r<A>;
|
||||
opcode_table[0xa0] = &CPU::op_and_a_r<B>;
|
||||
opcode_table[0xa1] = &CPU::op_and_a_r<C>;
|
||||
opcode_table[0xa2] = &CPU::op_and_a_r<D>;
|
||||
opcode_table[0xa3] = &CPU::op_and_a_r<E>;
|
||||
opcode_table[0xa4] = &CPU::op_and_a_r<H>;
|
||||
opcode_table[0xa5] = &CPU::op_and_a_r<L>;
|
||||
opcode_table[0xa6] = &CPU::op_and_a_hl;
|
||||
opcode_table[0xa7] = &CPU::op_and_a_r<A>;
|
||||
opcode_table[0xa8] = &CPU::op_xor_a_r<B>;
|
||||
opcode_table[0xa9] = &CPU::op_xor_a_r<C>;
|
||||
opcode_table[0xaa] = &CPU::op_xor_a_r<D>;
|
||||
opcode_table[0xab] = &CPU::op_xor_a_r<E>;
|
||||
opcode_table[0xac] = &CPU::op_xor_a_r<H>;
|
||||
opcode_table[0xad] = &CPU::op_xor_a_r<L>;
|
||||
opcode_table[0xae] = &CPU::op_xor_a_hl;
|
||||
opcode_table[0xaf] = &CPU::op_xor_a_r<A>;
|
||||
opcode_table[0xb0] = &CPU::op_or_a_r<B>;
|
||||
opcode_table[0xb1] = &CPU::op_or_a_r<C>;
|
||||
opcode_table[0xb2] = &CPU::op_or_a_r<D>;
|
||||
opcode_table[0xb3] = &CPU::op_or_a_r<E>;
|
||||
opcode_table[0xb4] = &CPU::op_or_a_r<H>;
|
||||
opcode_table[0xb5] = &CPU::op_or_a_r<L>;
|
||||
opcode_table[0xb6] = &CPU::op_or_a_hl;
|
||||
opcode_table[0xb7] = &CPU::op_or_a_r<A>;
|
||||
opcode_table[0xb8] = &CPU::op_cp_a_r<B>;
|
||||
opcode_table[0xb9] = &CPU::op_cp_a_r<C>;
|
||||
opcode_table[0xba] = &CPU::op_cp_a_r<D>;
|
||||
opcode_table[0xbb] = &CPU::op_cp_a_r<E>;
|
||||
opcode_table[0xbc] = &CPU::op_cp_a_r<H>;
|
||||
opcode_table[0xbd] = &CPU::op_cp_a_r<L>;
|
||||
opcode_table[0xbe] = &CPU::op_cp_a_hl;
|
||||
opcode_table[0xbf] = &CPU::op_cp_a_r<A>;
|
||||
opcode_table[0xc0] = &CPU::op_ret_f<ZF, 0>;
|
||||
opcode_table[0xc1] = &CPU::op_pop_rr<BC>;
|
||||
opcode_table[0xc2] = &CPU::op_jp_f_nn<ZF, 0>;
|
||||
opcode_table[0xc3] = &CPU::op_jp_nn;
|
||||
opcode_table[0xc4] = &CPU::op_call_f_nn<ZF, 0>;
|
||||
opcode_table[0xc5] = &CPU::op_push_rr<BC>;
|
||||
opcode_table[0xc6] = &CPU::op_add_a_n;
|
||||
opcode_table[0xc7] = &CPU::op_rst_n<0x00>;
|
||||
opcode_table[0xc8] = &CPU::op_ret_f<ZF, 1>;
|
||||
opcode_table[0xc9] = &CPU::op_ret;
|
||||
opcode_table[0xca] = &CPU::op_jp_f_nn<ZF, 1>;
|
||||
opcode_table[0xcb] = &CPU::op_cb;
|
||||
opcode_table[0xcc] = &CPU::op_call_f_nn<ZF, 1>;
|
||||
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<CF, 0>;
|
||||
opcode_table[0xd1] = &CPU::op_pop_rr<DE>;
|
||||
opcode_table[0xd2] = &CPU::op_jp_f_nn<CF, 0>;
|
||||
opcode_table[0xd3] = &CPU::op_xx;
|
||||
opcode_table[0xd4] = &CPU::op_call_f_nn<CF, 0>;
|
||||
opcode_table[0xd5] = &CPU::op_push_rr<DE>;
|
||||
opcode_table[0xd6] = &CPU::op_sub_a_n;
|
||||
opcode_table[0xd7] = &CPU::op_rst_n<0x10>;
|
||||
opcode_table[0xd8] = &CPU::op_ret_f<CF, 1>;
|
||||
opcode_table[0xd9] = &CPU::op_reti;
|
||||
opcode_table[0xda] = &CPU::op_jp_f_nn<CF, 1>;
|
||||
opcode_table[0xdb] = &CPU::op_xx;
|
||||
opcode_table[0xdc] = &CPU::op_call_f_nn<CF, 1>;
|
||||
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<HL>;
|
||||
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<HL>;
|
||||
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<AF>;
|
||||
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<AF>;
|
||||
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<B>;
|
||||
opcode_table_cb[0x01] = &CPU::op_rlc_r<C>;
|
||||
opcode_table_cb[0x02] = &CPU::op_rlc_r<D>;
|
||||
opcode_table_cb[0x03] = &CPU::op_rlc_r<E>;
|
||||
opcode_table_cb[0x04] = &CPU::op_rlc_r<H>;
|
||||
opcode_table_cb[0x05] = &CPU::op_rlc_r<L>;
|
||||
opcode_table_cb[0x06] = &CPU::op_rlc_hl;
|
||||
opcode_table_cb[0x07] = &CPU::op_rlc_r<A>;
|
||||
opcode_table_cb[0x08] = &CPU::op_rrc_r<B>;
|
||||
opcode_table_cb[0x09] = &CPU::op_rrc_r<C>;
|
||||
opcode_table_cb[0x0a] = &CPU::op_rrc_r<D>;
|
||||
opcode_table_cb[0x0b] = &CPU::op_rrc_r<E>;
|
||||
opcode_table_cb[0x0c] = &CPU::op_rrc_r<H>;
|
||||
opcode_table_cb[0x0d] = &CPU::op_rrc_r<L>;
|
||||
opcode_table_cb[0x0e] = &CPU::op_rrc_hl;
|
||||
opcode_table_cb[0x0f] = &CPU::op_rrc_r<A>;
|
||||
opcode_table_cb[0x10] = &CPU::op_rl_r<B>;
|
||||
opcode_table_cb[0x11] = &CPU::op_rl_r<C>;
|
||||
opcode_table_cb[0x12] = &CPU::op_rl_r<D>;
|
||||
opcode_table_cb[0x13] = &CPU::op_rl_r<E>;
|
||||
opcode_table_cb[0x14] = &CPU::op_rl_r<H>;
|
||||
opcode_table_cb[0x15] = &CPU::op_rl_r<L>;
|
||||
opcode_table_cb[0x16] = &CPU::op_rl_hl;
|
||||
opcode_table_cb[0x17] = &CPU::op_rl_r<A>;
|
||||
opcode_table_cb[0x18] = &CPU::op_rr_r<B>;
|
||||
opcode_table_cb[0x19] = &CPU::op_rr_r<C>;
|
||||
opcode_table_cb[0x1a] = &CPU::op_rr_r<D>;
|
||||
opcode_table_cb[0x1b] = &CPU::op_rr_r<E>;
|
||||
opcode_table_cb[0x1c] = &CPU::op_rr_r<H>;
|
||||
opcode_table_cb[0x1d] = &CPU::op_rr_r<L>;
|
||||
opcode_table_cb[0x1e] = &CPU::op_rr_hl;
|
||||
opcode_table_cb[0x1f] = &CPU::op_rr_r<A>;
|
||||
opcode_table_cb[0x20] = &CPU::op_sla_r<B>;
|
||||
opcode_table_cb[0x21] = &CPU::op_sla_r<C>;
|
||||
opcode_table_cb[0x22] = &CPU::op_sla_r<D>;
|
||||
opcode_table_cb[0x23] = &CPU::op_sla_r<E>;
|
||||
opcode_table_cb[0x24] = &CPU::op_sla_r<H>;
|
||||
opcode_table_cb[0x25] = &CPU::op_sla_r<L>;
|
||||
opcode_table_cb[0x26] = &CPU::op_sla_hl;
|
||||
opcode_table_cb[0x27] = &CPU::op_sla_r<A>;
|
||||
opcode_table_cb[0x28] = &CPU::op_sra_r<B>;
|
||||
opcode_table_cb[0x29] = &CPU::op_sra_r<C>;
|
||||
opcode_table_cb[0x2a] = &CPU::op_sra_r<D>;
|
||||
opcode_table_cb[0x2b] = &CPU::op_sra_r<E>;
|
||||
opcode_table_cb[0x2c] = &CPU::op_sra_r<H>;
|
||||
opcode_table_cb[0x2d] = &CPU::op_sra_r<L>;
|
||||
opcode_table_cb[0x2e] = &CPU::op_sra_hl;
|
||||
opcode_table_cb[0x2f] = &CPU::op_sra_r<A>;
|
||||
opcode_table_cb[0x30] = &CPU::op_swap_r<B>;
|
||||
opcode_table_cb[0x31] = &CPU::op_swap_r<C>;
|
||||
opcode_table_cb[0x32] = &CPU::op_swap_r<D>;
|
||||
opcode_table_cb[0x33] = &CPU::op_swap_r<E>;
|
||||
opcode_table_cb[0x34] = &CPU::op_swap_r<H>;
|
||||
opcode_table_cb[0x35] = &CPU::op_swap_r<L>;
|
||||
opcode_table_cb[0x36] = &CPU::op_swap_hl;
|
||||
opcode_table_cb[0x37] = &CPU::op_swap_r<A>;
|
||||
opcode_table_cb[0x38] = &CPU::op_srl_r<B>;
|
||||
opcode_table_cb[0x39] = &CPU::op_srl_r<C>;
|
||||
opcode_table_cb[0x3a] = &CPU::op_srl_r<D>;
|
||||
opcode_table_cb[0x3b] = &CPU::op_srl_r<E>;
|
||||
opcode_table_cb[0x3c] = &CPU::op_srl_r<H>;
|
||||
opcode_table_cb[0x3d] = &CPU::op_srl_r<L>;
|
||||
opcode_table_cb[0x3e] = &CPU::op_srl_hl;
|
||||
opcode_table_cb[0x3f] = &CPU::op_srl_r<A>;
|
||||
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
|
|
@ -0,0 +1,133 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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 <libco/libco.h>
|
||||
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
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 <gameboy/memory/memory.hpp>
|
||||
#include <gameboy/system/system.hpp>
|
||||
#include <gameboy/scheduler/scheduler.hpp>
|
||||
#include <gameboy/cartridge/cartridge.hpp>
|
||||
#include <gameboy/cpu/cpu.hpp>
|
||||
#include <gameboy/lcd/lcd.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"); }
|
||||
};
|
|
@ -0,0 +1,224 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
|
@ -0,0 +1,60 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#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() {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,33 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,44 @@
|
|||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <gameboy/interface/interface.hpp>
|
||||
|
||||
extern System system;
|
|
@ -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 #
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define DSP_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define PPU_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define PPU_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include <nall/crc32.hpp>
|
||||
#include <nall/sha256.hpp>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CHEAT_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define BSX_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -3,21 +3,21 @@ struct Coprocessor : Processor {
|
|||
alwaysinline void synchronize_cpu();
|
||||
};
|
||||
|
||||
#include <chip/supergameboy/supergameboy.hpp>
|
||||
#include <chip/superfx/superfx.hpp>
|
||||
#include <chip/sa1/sa1.hpp>
|
||||
#include <chip/upd77c25/upd77c25.hpp>
|
||||
#include <chip/bsx/bsx.hpp>
|
||||
#include <chip/srtc/srtc.hpp>
|
||||
#include <chip/sdd1/sdd1.hpp>
|
||||
#include <chip/spc7110/spc7110.hpp>
|
||||
#include <chip/cx4/cx4.hpp>
|
||||
#include <chip/obc1/obc1.hpp>
|
||||
#include <chip/st0010/st0010.hpp>
|
||||
#include <chip/st0011/st0011.hpp>
|
||||
#include <chip/st0018/st0018.hpp>
|
||||
#include <chip/msu1/msu1.hpp>
|
||||
#include <chip/serial/serial.hpp>
|
||||
#include <snes/chip/icd2/icd2.hpp>
|
||||
#include <snes/chip/superfx/superfx.hpp>
|
||||
#include <snes/chip/sa1/sa1.hpp>
|
||||
#include <snes/chip/upd77c25/upd77c25.hpp>
|
||||
#include <snes/chip/bsx/bsx.hpp>
|
||||
#include <snes/chip/srtc/srtc.hpp>
|
||||
#include <snes/chip/sdd1/sdd1.hpp>
|
||||
#include <snes/chip/spc7110/spc7110.hpp>
|
||||
#include <snes/chip/cx4/cx4.hpp>
|
||||
#include <snes/chip/obc1/obc1.hpp>
|
||||
#include <snes/chip/st0010/st0010.hpp>
|
||||
#include <snes/chip/st0011/st0011.hpp>
|
||||
#include <snes/chip/st0018/st0018.hpp>
|
||||
#include <snes/chip/msu1/msu1.hpp>
|
||||
#include <snes/chip/serial/serial.hpp>
|
||||
|
||||
void Coprocessor::step(unsigned clocks) {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//Used in Rockman X2/X3 (Megaman X2/X3)
|
||||
//Portions (c) anomie, Overload, zsKnight, Nach, byuu
|
||||
|
||||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CX4_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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];
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define MSU1_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define OBC1_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SA1_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SDD1_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SERIAL_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SPC7110_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SRTC_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define ST0010_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define ST0011_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define ST0018_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SUPERFX_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -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
|
|
@ -1,141 +0,0 @@
|
|||
#include <snes.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<void (uint8_t*, unsigned)> sgb_rom;
|
||||
function<void (uint8_t*, unsigned)> sgb_ram;
|
||||
function<void (uint8_t*, unsigned)> sgb_rtc;
|
||||
function<bool (bool)> sgb_init;
|
||||
function<void ()> sgb_term;
|
||||
function<void ()> sgb_power;
|
||||
function<void ()> sgb_reset;
|
||||
function<void (unsigned)> sgb_row;
|
||||
function<uint8 (uint16)> sgb_read;
|
||||
function<void (uint16, uint8)> sgb_write;
|
||||
function<unsigned (uint32_t*, unsigned)> sgb_run;
|
||||
function<void ()> sgb_save;
|
||||
function<void (serializer&)> sgb_serialize;
|
||||
|
||||
friend class Cartridge;
|
||||
};
|
||||
|
||||
extern SuperGameBoy supergameboy;
|
|
@ -7,7 +7,7 @@
|
|||
//* interrupts
|
||||
//* DMA
|
||||
|
||||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define UPD77C25_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CPUCORE_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define DSP_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define MEMORY_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define PPU_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Info {
|
|||
static const char Profile[] = "Accuracy";
|
||||
}
|
||||
|
||||
#include <cpu/cpu.hpp>
|
||||
#include <smp/smp.hpp>
|
||||
#include <dsp/dsp.hpp>
|
||||
#include <ppu/ppu.hpp>
|
||||
#include <snes/cpu/cpu.hpp>
|
||||
#include <snes/smp/smp.hpp>
|
||||
#include <snes/dsp/dsp.hpp>
|
||||
#include <snes/ppu/ppu.hpp>
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Info {
|
|||
static const char Profile[] = "Compatibility";
|
||||
}
|
||||
|
||||
#include <cpu/cpu.hpp>
|
||||
#include <smp/smp.hpp>
|
||||
#include <alt/dsp/dsp.hpp>
|
||||
#include <alt/ppu-compatibility/ppu.hpp>
|
||||
#include <snes/cpu/cpu.hpp>
|
||||
#include <snes/smp/smp.hpp>
|
||||
#include <snes/alt/dsp/dsp.hpp>
|
||||
#include <snes/alt/ppu-compatibility/ppu.hpp>
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Info {
|
|||
static const char Profile[] = "Performance";
|
||||
}
|
||||
|
||||
#include <alt/cpu/cpu.hpp>
|
||||
#include <smp/smp.hpp>
|
||||
#include <alt/dsp/dsp.hpp>
|
||||
#include <alt/ppu-performance/ppu.hpp>
|
||||
#include <snes/alt/cpu/cpu.hpp>
|
||||
#include <snes/smp/smp.hpp>
|
||||
#include <snes/alt/dsp/dsp.hpp>
|
||||
#include <snes/alt/ppu-performance/ppu.hpp>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SMPCORE_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SMP_CPP
|
||||
namespace SNES {
|
||||
|
|
|
@ -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 <nall/vector.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#ifdef DEBUGGER
|
||||
#define debugvirtual virtual
|
||||
#else
|
||||
|
@ -109,10 +111,10 @@ namespace SNES {
|
|||
virtual bool property(unsigned id, string &name, string &value) = 0;
|
||||
};
|
||||
|
||||
#include <memory/memory.hpp>
|
||||
#include <cpu/core/core.hpp>
|
||||
#include <smp/core/core.hpp>
|
||||
#include <ppu/counter/counter.hpp>
|
||||
#include <snes/memory/memory.hpp>
|
||||
#include <snes/cpu/core/core.hpp>
|
||||
#include <snes/smp/core/core.hpp>
|
||||
#include <snes/ppu/counter/counter.hpp>
|
||||
|
||||
#if defined(PROFILE_ACCURACY)
|
||||
#include "profile-accuracy.hpp"
|
||||
|
@ -122,14 +124,14 @@ namespace SNES {
|
|||
#include "profile-performance.hpp"
|
||||
#endif
|
||||
|
||||
#include <system/system.hpp>
|
||||
#include <chip/chip.hpp>
|
||||
#include <cartridge/cartridge.hpp>
|
||||
#include <cheat/cheat.hpp>
|
||||
#include <snes/system/system.hpp>
|
||||
#include <snes/chip/chip.hpp>
|
||||
#include <snes/cartridge/cartridge.hpp>
|
||||
#include <snes/cheat/cheat.hpp>
|
||||
|
||||
#include <memory/memory-inline.hpp>
|
||||
#include <ppu/counter/counter-inline.hpp>
|
||||
#include <cheat/cheat-inline.hpp>
|
||||
#include <snes/memory/memory-inline.hpp>
|
||||
#include <snes/ppu/counter/counter-inline.hpp>
|
||||
#include <snes/cheat/cheat-inline.hpp>
|
||||
}
|
||||
|
||||
namespace nall {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#define SYSTEM_CPP
|
||||
namespace SNES {
|
||||
|
||||
System system;
|
||||
|
||||
#include <config/config.cpp>
|
||||
#include <debugger/debugger.cpp>
|
||||
#include <scheduler/scheduler.cpp>
|
||||
#include <snes/config/config.cpp>
|
||||
#include <snes/debugger/debugger.cpp>
|
||||
#include <snes/scheduler/scheduler.cpp>
|
||||
|
||||
#include <video/video.cpp>
|
||||
#include <audio/audio.cpp>
|
||||
#include <input/input.cpp>
|
||||
#include <snes/video/video.cpp>
|
||||
#include <snes/audio/audio.cpp>
|
||||
#include <snes/input/input.cpp>
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
|
@ -68,7 +68,7 @@ void System::init(Interface *interface_) {
|
|||
interface = interface_;
|
||||
assert(interface != 0);
|
||||
|
||||
supergameboy.init();
|
||||
icd2.init();
|
||||
superfx.init();
|
||||
sa1.init();
|
||||
upd77c25.init();
|
||||
|
@ -119,7 +119,7 @@ void System::power() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxbase.enable();
|
||||
if(memory::bsxflash.data()) bsxflash.enable();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.enable();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.enable();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.enable();
|
||||
|
||||
if(cartridge.has_superfx()) superfx.enable();
|
||||
if(cartridge.has_sa1()) sa1.enable();
|
||||
|
@ -143,7 +143,7 @@ void System::power() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxbase.power();
|
||||
if(memory::bsxflash.data()) bsxflash.power();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.power();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.power();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power();
|
||||
|
||||
if(cartridge.has_superfx()) superfx.power();
|
||||
if(cartridge.has_sa1()) sa1.power();
|
||||
|
@ -159,7 +159,7 @@ void System::power() {
|
|||
if(cartridge.has_msu1()) msu1.power();
|
||||
if(cartridge.has_serial()) serial.power();
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy);
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
|
||||
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_upd77c25()) cpu.coprocessors.append(&upd77c25);
|
||||
|
@ -182,7 +182,7 @@ void System::reset() {
|
|||
if(expansion() == ExpansionPortDevice::BSX) bsxbase.reset();
|
||||
if(memory::bsxflash.data()) bsxflash.reset();
|
||||
if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcart.reset();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.reset();
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset();
|
||||
|
||||
if(cartridge.has_superfx()) superfx.reset();
|
||||
if(cartridge.has_sa1()) sa1.reset();
|
||||
|
@ -198,7 +198,7 @@ void System::reset() {
|
|||
if(cartridge.has_msu1()) msu1.reset();
|
||||
if(cartridge.has_serial()) serial.reset();
|
||||
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy);
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2);
|
||||
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_upd77c25()) cpu.coprocessors.append(&upd77c25);
|
||||
|
@ -214,7 +214,7 @@ void System::reset() {
|
|||
}
|
||||
|
||||
void System::unload() {
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.unload();
|
||||
//if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.unload();
|
||||
}
|
||||
|
||||
void System::scanline() {
|
||||
|
|
|
@ -43,13 +43,13 @@ private:
|
|||
friend class Input;
|
||||
};
|
||||
|
||||
#include <video/video.hpp>
|
||||
#include <audio/audio.hpp>
|
||||
#include <input/input.hpp>
|
||||
#include <snes/video/video.hpp>
|
||||
#include <snes/audio/audio.hpp>
|
||||
#include <snes/input/input.hpp>
|
||||
|
||||
#include <config/config.hpp>
|
||||
#include <debugger/debugger.hpp>
|
||||
#include <interface/interface.hpp>
|
||||
#include <scheduler/scheduler.hpp>
|
||||
#include <snes/config/config.hpp>
|
||||
#include <snes/debugger/debugger.hpp>
|
||||
#include <snes/interface/interface.hpp>
|
||||
#include <snes/scheduler/scheduler.hpp>
|
||||
|
||||
extern System system;
|
||||
|
|
|
@ -18,3 +18,5 @@ rm -r phoenix/test*
|
|||
rm -r phoenix/*.sh
|
||||
rm -r phoenix/*.bat
|
||||
|
||||
test -d gameboy && rm -r gameboy
|
||||
cp -r ../bgameboy/gameboy ./gameboy
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include <nall/base64.hpp>
|
||||
#include <nall/config.hpp>
|
||||
|
|
|
@ -13,7 +13,6 @@ void MainWindow::create() {
|
|||
systemLoadCartridgeBsx.create(systemLoadCartridgeSpecial, "Load BS-X Cartridge ...");
|
||||
systemLoadCartridgeSufamiTurbo.create(systemLoadCartridgeSpecial, "Load Sufami Turbo Cartridge ...");
|
||||
systemLoadCartridgeSuperGameBoy.create(systemLoadCartridgeSpecial, "Load Super Game Boy Cartridge ...");
|
||||
systemLoadCartridgeSuperGameBoy.setEnabled(SNES::supergameboy.opened());
|
||||
systemSeparator1.create(system);
|
||||
systemPower.create(system, "Power Cycle");
|
||||
systemReset.create(system, "Reset");
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
include nall/Makefile
|
||||
|
||||
c := $(compiler) -std=gnu99
|
||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||
flags := -O3 -fomit-frame-pointer -I. -Icommon -Ilibgambatte/include -Ilibgambatte/src
|
||||
link :=
|
||||
|
||||
ifeq ($(platform),osx)
|
||||
flags := -fPIC $(flags)
|
||||
else ifeq ($(platform),x)
|
||||
flags := -fPIC $(flags)
|
||||
link += -s
|
||||
endif
|
||||
|
||||
objects := supergameboy
|
||||
objects += bitmap_font colorconversion cpu gambatte initstate interrupter
|
||||
objects += memory rtc sound state_osd_elements statesaver video
|
||||
objects += channel1 channel2 channel3 channel4 duty_unit envelope_unit length_counter
|
||||
objects += basic_add_event break_event irq_event ly_counter lyc_irq
|
||||
objects += m3_extra_cycles mode3_event mode0_irq mode1_irq mode2_irq
|
||||
objects += sc_reader scx_reader sprite_mapper we_master_checker we wx_reader wy
|
||||
objects += catrom2x catrom3x kreed2xsai maxsthq2x maxsthq3x file
|
||||
|
||||
compile = \
|
||||
$(strip \
|
||||
$(if $(filter %.c,$<), \
|
||||
$(c) $(flags) $1 -c $< -o $@, \
|
||||
$(if $(filter %.cpp,$<), \
|
||||
$(cpp) $(flags) $1 -c $< -o $@ \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
%.o: $<; $(call compile)
|
||||
|
||||
all: build;
|
||||
|
||||
objects := $(patsubst %,obj/%.o,$(objects))
|
||||
|
||||
####################
|
||||
### supergameboy ###
|
||||
####################
|
||||
|
||||
obj/supergameboy.o: supergameboy.cpp *.cpp *.hpp $(call rwildcard,interface/)
|
||||
|
||||
###################
|
||||
### libgambatte ###
|
||||
###################
|
||||
|
||||
obj/bitmap_font.o: libgambatte/src/bitmap_font.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/colorconversion.o: libgambatte/src/colorconversion.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/cpu.o: libgambatte/src/cpu.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/gambatte.o: libgambatte/src/gambatte.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/initstate.o: libgambatte/src/initstate.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/interrupter.o: libgambatte/src/interrupter.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/memory.o: libgambatte/src/memory.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/rtc.o: libgambatte/src/rtc.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/sound.o: libgambatte/src/sound.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/state_osd_elements.o: libgambatte/src/state_osd_elements.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/statesaver.o: libgambatte/src/statesaver.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/video.o: libgambatte/src/video.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
|
||||
obj/channel1.o: libgambatte/src/sound/channel1.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/channel2.o: libgambatte/src/sound/channel2.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/channel3.o: libgambatte/src/sound/channel3.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/channel4.o: libgambatte/src/sound/channel4.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/duty_unit.o: libgambatte/src/sound/duty_unit.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/envelope_unit.o: libgambatte/src/sound/envelope_unit.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/length_counter.o: libgambatte/src/sound/length_counter.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
|
||||
obj/basic_add_event.o: libgambatte/src/video/basic_add_event.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/break_event.o: libgambatte/src/video/break_event.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/irq_event.o: libgambatte/src/video/irq_event.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/ly_counter.o: libgambatte/src/video/ly_counter.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/lyc_irq.o: libgambatte/src/video/lyc_irq.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/m3_extra_cycles.o: libgambatte/src/video/m3_extra_cycles.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/mode3_event.o: libgambatte/src/video/mode3_event.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/mode0_irq.o: libgambatte/src/video/mode0_irq.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/mode1_irq.o: libgambatte/src/video/mode1_irq.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/mode2_irq.o: libgambatte/src/video/mode2_irq.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/sc_reader.o: libgambatte/src/video/sc_reader.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/scx_reader.o: libgambatte/src/video/scx_reader.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/sprite_mapper.o: libgambatte/src/video/sprite_mapper.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/we_master_checker.o: libgambatte/src/video/we_master_checker.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/we.o: libgambatte/src/video/we.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/wx_reader.o: libgambatte/src/video/wx_reader.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/wy.o: libgambatte/src/video/wy.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
|
||||
obj/catrom2x.o: libgambatte/src/video/filters/catrom2x.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/catrom3x.o: libgambatte/src/video/filters/catrom3x.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/kreed2xsai.o: libgambatte/src/video/filters/kreed2xsai.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/maxsthq2x.o: libgambatte/src/video/filters/maxsthq2x.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
obj/maxsthq3x.o: libgambatte/src/video/filters/maxsthq3x.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
|
||||
obj/file.o: libgambatte/src/file/file.cpp $(call rwildcard,common/) $(call rwildcard,libgambatte/)
|
||||
|
||||
###############
|
||||
### targets ###
|
||||
###############
|
||||
|
||||
build: $(objects)
|
||||
ifeq ($(platform),win)
|
||||
$(cpp) $(link) -o supergameboy.dll -shared -Wl,--out-implib,libsupergameboy.a $(objects) $(qtlib)
|
||||
else ifeq ($(platform),osx)
|
||||
ar rcs libsupergameboy.a $(objects)
|
||||
$(cpp) $(link) -o libsupergameboy.dylib -shared -dynamiclib $(objects) $(qtlib)
|
||||
else
|
||||
ar rcs libsupergameboy.a $(objects)
|
||||
$(cpp) $(link) -o libsupergameboy.so -shared -Wl,-soname,libsupergameboy.so.1 $(objects) $(qtlib)
|
||||
endif
|
||||
|
||||
install:
|
||||
ifeq ($(platform),osx)
|
||||
cp libsupergameboy.dylib /usr/local/lib/libsupergameboy.dylib
|
||||
else
|
||||
install -D -m 755 libsupergameboy.a $(DESTDIR)$(prefix)/lib
|
||||
install -D -m 755 libsupergameboy.so $(DESTDIR)$(prefix)/lib
|
||||
ldconfig -n $(DESTDIR)$(prefix)/lib
|
||||
endif
|
||||
|
||||
clean:
|
||||
-@$(call delete,obj/*.o)
|
||||
-@$(call delete,libsupergameboy.a)
|
||||
-@$(call delete,supergameboy.dll)
|
||||
-@$(call delete,libsupergameboy.dylib)
|
||||
-@$(call delete,libsupergameboy.so)
|
|
@ -1,2 +0,0 @@
|
|||
@mingw32-make
|
||||
@pause
|
|
@ -1 +0,0 @@
|
|||
@mingw32-make clean
|
|
@ -1,56 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "adaptivesleep.h"
|
||||
|
||||
usec_t AdaptiveSleep::sleepUntil(usec_t base, usec_t inc) {
|
||||
usec_t now = getusecs();
|
||||
usec_t diff = now - base;
|
||||
|
||||
if (diff >= inc)
|
||||
return diff - inc;
|
||||
|
||||
diff = inc - diff;
|
||||
|
||||
if (diff > oversleep + oversleepVar) {
|
||||
diff -= oversleep + oversleepVar;
|
||||
usecsleep(diff);
|
||||
const usec_t ideal = now + diff;
|
||||
now = getusecs();
|
||||
|
||||
{
|
||||
usec_t curOversleep = now - ideal;
|
||||
|
||||
if (negate(curOversleep) < curOversleep)
|
||||
curOversleep = 0;
|
||||
|
||||
oversleepVar = (oversleepVar * 15 + (curOversleep < oversleep ? oversleep - curOversleep : curOversleep - oversleep)) >> 4;
|
||||
oversleep = (oversleep * 15 + curOversleep) >> 4;
|
||||
}
|
||||
|
||||
noSleep = 60;
|
||||
} else if (--noSleep == 0) {
|
||||
noSleep = 60;
|
||||
oversleep = oversleepVar = 0;
|
||||
}
|
||||
|
||||
while (now - base < inc)
|
||||
now = getusecs();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ADAPTIVE_SLEEP_H
|
||||
#define ADAPTIVE_SLEEP_H
|
||||
|
||||
#include "usec.h"
|
||||
|
||||
class AdaptiveSleep {
|
||||
usec_t oversleep;
|
||||
usec_t oversleepVar;
|
||||
unsigned noSleep;
|
||||
|
||||
public:
|
||||
AdaptiveSleep() : oversleep(0), oversleepVar(0), noSleep(60) {}
|
||||
usec_t sleepUntil(usec_t base, usec_t inc);
|
||||
};
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue