Update to release v000r10.

byuu says:

Changelog:
- fixed LYC interrupt at LY=0 (fixes Makai Toushi SaGa)
- fixed MBC3 ROM bank mapping (fixes Harvest Moon GBC)
- added Super Game Boy MLT_REQ support to JOYP, needed for ICD2-R emulation
- temporarily changed System::run() to execute only four cycles before
  exiting for bsnes, will make two versions later
- uses actual boot ROMs, has DMG+SGB1 for now. Need SGB2, don't care
  about CGB. Defaults to SGB1, no way to select just yet.  DMG 4-second
  wait is annoying. Does not force games to act like SGB on bgameboy
  itself, because that has no ICD2 and fails the required MLT_REQ check
This commit is contained in:
Tim Allen 2011-01-06 21:16:07 +11:00
parent 2d49a4408d
commit f0796e546e
17 changed files with 104 additions and 22 deletions

View File

@ -7,7 +7,7 @@ c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
flags := -O3 -fomit-frame-pointer -I. flags := -O3 -fomit-frame-pointer -I.
link := link :=
objects := objects := libco
# profile-guided instrumentation # profile-guided instrumentation
# flags += -fprofile-generate # flags += -fprofile-generate
@ -44,6 +44,8 @@ compile = \
all: build; all: build;
obj/libco.o: libco/libco.c libco/*
include $(gameboy)/Makefile include $(gameboy)/Makefile
include $(ui)/Makefile include $(ui)/Makefile

View File

@ -1,11 +1,8 @@
gameboy_objects := libco gameboy_objects := gameboy-system gameboy-scheduler
gameboy_objects += gameboy-system gameboy-scheduler
gameboy_objects += gameboy-memory gameboy-cartridge gameboy_objects += gameboy-memory gameboy-cartridge
gameboy_objects += gameboy-cpu gameboy-lcd gameboy_objects += gameboy-cpu gameboy-lcd
objects += $(gameboy_objects) objects += $(gameboy_objects)
obj/libco.o: libco/libco.c libco/*
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/) 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-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/)
obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/) obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/)

View File

@ -64,7 +64,7 @@ void Cartridge::load(uint8_t *data, unsigned size) {
case 0xfe: info.mapper = Mapper::HuC3; break; case 0xfe: info.mapper = Mapper::HuC3; break;
case 0xff: info.mapper = Mapper::HuC1; info.ram = true; info.battery = true; break; case 0xff: info.mapper = Mapper::HuC1; info.ram = true; info.battery = true; break;
} }
print("Mapper: ", hex<2>(romdata[0x0147]), "\n"); //print("Mapper: ", hex<2>(romdata[0x0147]), "\n");
switch(romdata[0x0148]) { default: switch(romdata[0x0148]) { default:
case 0x00: info.romsize = 2 * 16 * 1024; break; case 0x00: info.romsize = 2 * 16 * 1024; break;
@ -103,8 +103,6 @@ void Cartridge::unload() {
} }
uint8 Cartridge::rom_read(unsigned addr) { uint8 Cartridge::rom_read(unsigned addr) {
//if(addr >= 0x028000) print(hex<6>(addr), " - ", romsize, "\n");
if(addr >= romsize) addr %= romsize; if(addr >= romsize) addr %= romsize;
return romdata[addr]; return romdata[addr];
} }
@ -135,7 +133,10 @@ void Cartridge::power() {
mmm01.power(); mmm01.power();
huc1.power(); huc1.power();
huc3.power(); huc3.power();
map();
}
void Cartridge::map() {
MMIO *mapper = 0; MMIO *mapper = 0;
switch(info.mapper) { default: switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break; case Mapper::MBC0: mapper = &mbc0; break;

View File

@ -52,6 +52,7 @@ struct Cartridge : property<Cartridge> {
void ram_write(unsigned addr, uint8 data); void ram_write(unsigned addr, uint8 data);
void power(); void power();
void map();
Cartridge(); Cartridge();
~Cartridge(); ~Cartridge();

View File

@ -24,7 +24,7 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
} }
if((addr & 0xc000) == 0x4000) { //4000-7fff if((addr & 0xc000) == 0x4000) { //4000-7fff
return cartridge.rom_read((rom_select << 13) | (addr & 0x3fff)); return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
} }
if((addr & 0xe000) == 0xa000) { //a000-bfff if((addr & 0xe000) == 0xa000) { //a000-bfff

View File

@ -82,9 +82,9 @@ void CPU::power() {
for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00; for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00;
for(unsigned n = 0; n < 128; n++) hram[n] = 0x00; for(unsigned n = 0; n < 128; n++) hram[n] = 0x00;
r[PC] = 0x0100; r[PC] = 0x0000;
r[SP] = 0xfffe; r[SP] = 0x0000;
r[AF] = 0x0100; r[AF] = 0x0000;
r[BC] = 0x0000; r[BC] = 0x0000;
r[DE] = 0x0000; r[DE] = 0x0000;
r[HL] = 0x0000; r[HL] = 0x0000;
@ -102,6 +102,7 @@ void CPU::power() {
status.p15 = 0; status.p15 = 0;
status.p14 = 0; status.p14 = 0;
status.joyp = 0; status.joyp = 0;
status.mlt_req = 0;
status.div = 0; status.div = 0;

View File

@ -28,6 +28,7 @@ struct CPU : Processor, MMIO {
bool p15; bool p15;
bool p14; bool p14;
uint8 joyp; uint8 joyp;
uint8 mlt_req;
//$ff04 DIV //$ff04 DIV
uint8 div; uint8 div;

View File

@ -14,6 +14,7 @@ void CPU::mmio_joyp_poll() {
dpad |= system.interface->input_poll((unsigned)Input::Right) << 0; dpad |= system.interface->input_poll((unsigned)Input::Right) << 0;
status.joyp = 0x0f; 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.p15 == 0) status.joyp &= button ^ 0x0f;
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f; if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad); if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
@ -74,6 +75,7 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
if(addr == 0xff00) { //JOYP if(addr == 0xff00) { //JOYP
status.p15 = data & 0x20; status.p15 = data & 0x20;
status.p14 = data & 0x10; status.p14 = data & 0x10;
system.interface->joyp_write(status.p15, status.p14);
mmio_joyp_poll(); mmio_joyp_poll();
return; return;
} }

View File

@ -13,6 +13,9 @@
#include "opcode.cpp" #include "opcode.cpp"
void CPU::add_clocks(unsigned clocks) { void CPU::add_clocks(unsigned clocks) {
system.clocks_executed += clocks;
scheduler.exit();
status.clock += clocks; status.clock += clocks;
if(status.clock >= 4 * 1024 * 1024) { if(status.clock >= 4 * 1024 * 1024) {
status.clock -= 4 * 1024 * 1024; status.clock -= 4 * 1024 * 1024;

View File

@ -5,7 +5,7 @@
namespace GameBoy { namespace GameBoy {
namespace Info { namespace Info {
static const char Name[] = "bgameboy"; static const char Name[] = "bgameboy";
static const char Version[] = "000.09"; static const char Version[] = "000.10";
} }
} }
@ -43,9 +43,9 @@ namespace GameBoy {
inline Processor() : thread(0) {} inline Processor() : thread(0) {}
}; };
#include <gameboy/memory/memory.hpp>
#include <gameboy/system/system.hpp> #include <gameboy/system/system.hpp>
#include <gameboy/scheduler/scheduler.hpp> #include <gameboy/scheduler/scheduler.hpp>
#include <gameboy/memory/memory.hpp>
#include <gameboy/cartridge/cartridge.hpp> #include <gameboy/cartridge/cartridge.hpp>
#include <gameboy/cpu/cpu.hpp> #include <gameboy/cpu/cpu.hpp>
#include <gameboy/lcd/lcd.hpp> #include <gameboy/lcd/lcd.hpp>

View File

@ -1,5 +1,7 @@
class Interface { class Interface {
public: public:
virtual void joyp_write(bool p15, bool p14) {}
virtual void video_refresh(const uint8_t *data) {} virtual void video_refresh(const uint8_t *data) {}
virtual void audio_sample(signed left, signed right) {} virtual void audio_sample(signed left, signed right) {}
virtual void input_poll() {} virtual void input_poll() {}

View File

@ -30,19 +30,18 @@ void LCD::add_clocks(unsigned clocks) {
void LCD::scanline() { void LCD::scanline() {
status.lx -= 456; status.lx -= 456;
status.ly++; if(++status.ly == 154) frame();
if(status.interrupt_lyc == true) { if(status.interrupt_lyc == true) {
if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat); if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat);
} }
if(status.ly < 144) render();
if(status.ly == 144) { if(status.ly == 144) {
cpu.interrupt_raise(CPU::Interrupt::Vblank); cpu.interrupt_raise(CPU::Interrupt::Vblank);
if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat); if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
} }
if(status.ly == 154) frame();
if(status.ly < 144) render();
} }
void LCD::frame() { void LCD::frame() {

23
gameboy/system/bootrom-dmg.cpp Executable file
View File

@ -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

23
gameboy/system/bootrom-sgb.cpp Executable file
View File

@ -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

View File

@ -3,8 +3,23 @@
#define SYSTEM_CPP #define SYSTEM_CPP
namespace GameBoy { namespace GameBoy {
#include "bootrom-dmg.cpp"
#include "bootrom-sgb.cpp"
System system; 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_) { void System::init(Interface *interface_) {
interface = interface_; interface = interface_;
} }
@ -15,6 +30,11 @@ void System::power() {
cpu.power(); cpu.power();
lcd.power(); lcd.power();
scheduler.init(); scheduler.init();
for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this;
bus.mmio[0xff50] = this;
system.clocks_executed = 0;
} }
void System::run() { void System::run() {

View File

@ -4,14 +4,21 @@ enum class Input : unsigned {
Up, Down, Left, Right, B, A, Select, Start, Up, Down, Left, Right, B, A, Select, Start,
}; };
class System { struct System : MMIO {
public: 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 init(Interface*);
void power(); void power();
void run(); void run();
//private:
Interface *interface; Interface *interface;
unsigned clocks_executed;
}; };
#include <gameboy/interface/interface.hpp> #include <gameboy/interface/interface.hpp>

View File

@ -46,7 +46,7 @@ void Application::main(int argc, char **argv) {
OS::run(); OS::run();
if(GameBoy::cartridge.loaded()) { if(GameBoy::cartridge.loaded()) {
GameBoy::system.run(); for(unsigned n = 0; n < 1024 * 1024; n++) GameBoy::system.run();
} }
} }
} }