mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-18 08:01:42 +02:00
Update to release v000r07.
byuu says: Changelog: - fixed sprite Vflip check - fixed up window rendering (well, mostly, works great in Megaman II but not so great in Makaitoushi SaGa) - added MBC2, MBC5 (already had MBC0, MBC1) - removed reset, hooked up power cycle and Vsync toggle - some other stuff Makaitoushi SaGa locks on the main menu after some graphical glitches on the title screen, damn. Shin Megami Tensei - Devichil Black Book locks up immediately, hitting HALT opcodes all the time, damn again. Megaman II should be fully playable now. Contra 3 is really close, but goes crazy on the turtle boss fight.
This commit is contained in:
2
Makefile
2
Makefile
@@ -5,7 +5,7 @@ ui := ui
|
|||||||
# compiler
|
# compiler
|
||||||
c := $(compiler) -std=gnu99
|
c := $(compiler) -std=gnu99
|
||||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||||
flags := -O3 -fomit-frame-pointer -I. -I$(gameboy)
|
flags := -O3 -fomit-frame-pointer -I.
|
||||||
link :=
|
link :=
|
||||||
objects :=
|
objects :=
|
||||||
|
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define CARTRIDGE_CPP
|
#define CARTRIDGE_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
|
||||||
#include "mbc0/mbc0.cpp"
|
#include "mbc0/mbc0.cpp"
|
||||||
#include "mbc1/mbc1.cpp"
|
#include "mbc1/mbc1.cpp"
|
||||||
|
#include "mbc2/mbc2.cpp"
|
||||||
|
#include "mbc5/mbc5.cpp"
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
void Cartridge::load(uint8_t *data, unsigned size) {
|
void Cartridge::load(uint8_t *data, unsigned size) {
|
||||||
@@ -25,11 +27,20 @@ void Cartridge::load(uint8_t *data, unsigned size) {
|
|||||||
info.battery = false;
|
info.battery = false;
|
||||||
info.rtc = false;
|
info.rtc = false;
|
||||||
|
|
||||||
switch(romdata[0x0147]) { default:
|
switch(romdata[0x0147]) {
|
||||||
case 0x00: info.mapper = Mapper::MBC0; break;
|
case 0x00: info.mapper = Mapper::MBC0; break;
|
||||||
case 0x01: info.mapper = Mapper::MBC1; break;
|
case 0x01: info.mapper = Mapper::MBC1; break;
|
||||||
case 0x02: info.mapper = Mapper::MBC1; info.ram = true; 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 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 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;
|
||||||
|
default: print("Unknown mapper: ", hex<2>(romdata[0x0147]), "\n"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(romdata[0x0148]) { default:
|
switch(romdata[0x0148]) { default:
|
||||||
@@ -46,7 +57,6 @@ void Cartridge::load(uint8_t *data, unsigned size) {
|
|||||||
case 0x54: info.romsize = 96 * 16 * 1024; break;
|
case 0x54: info.romsize = 96 * 16 * 1024; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: MBC2 always stores 0x00 here; yet it has 512x4-bits RAM
|
|
||||||
switch(romdata[0x0149]) { default:
|
switch(romdata[0x0149]) { default:
|
||||||
case 0x00: info.ramsize = 0 * 1024; break;
|
case 0x00: info.ramsize = 0 * 1024; break;
|
||||||
case 0x01: info.ramsize = 2 * 1024; break;
|
case 0x01: info.ramsize = 2 * 1024; break;
|
||||||
@@ -54,6 +64,8 @@ void Cartridge::load(uint8_t *data, unsigned size) {
|
|||||||
case 0x03: info.ramsize = 32 * 1024; break;
|
case 0x03: info.ramsize = 32 * 1024; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(info.mapper == Mapper::MBC2) info.ramsize = 256; //512 x 4-bit
|
||||||
|
|
||||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
@@ -92,23 +104,21 @@ void Cartridge::ram_write(unsigned addr, uint8 data) {
|
|||||||
void Cartridge::power() {
|
void Cartridge::power() {
|
||||||
mbc0.power();
|
mbc0.power();
|
||||||
mbc1.power();
|
mbc1.power();
|
||||||
|
mbc2.power();
|
||||||
|
mbc5.power();
|
||||||
|
|
||||||
MMIO *mapper = 0;
|
MMIO *mapper = 0;
|
||||||
switch(info.mapper) {
|
switch(info.mapper) { default:
|
||||||
case Mapper::MBC0: mapper = &mbc0; break;
|
case Mapper::MBC0: mapper = &mbc0; break;
|
||||||
case Mapper::MBC1: mapper = &mbc1; break;
|
case Mapper::MBC1: mapper = &mbc1; break;
|
||||||
|
case Mapper::MBC2: mapper = &mbc2; break;
|
||||||
|
case Mapper::MBC5: mapper = &mbc5; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mapper) {
|
if(mapper) {
|
||||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper;
|
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = mapper;
|
||||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper;
|
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cartridge::reset() {
|
|
||||||
mbc1.reset();
|
|
||||||
mbc1.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
|
@@ -1,22 +1,27 @@
|
|||||||
struct Cartridge : property<Cartridge> {
|
struct Cartridge : property<Cartridge> {
|
||||||
#include "mbc0/mbc0.hpp"
|
#include "mbc0/mbc0.hpp"
|
||||||
#include "mbc1/mbc1.hpp"
|
#include "mbc1/mbc1.hpp"
|
||||||
|
#include "mbc2/mbc2.hpp"
|
||||||
|
#include "mbc5/mbc5.hpp"
|
||||||
|
|
||||||
enum Mapper : unsigned {
|
enum Mapper : unsigned {
|
||||||
MBC0,
|
MBC0,
|
||||||
MBC1,
|
MBC1,
|
||||||
|
MBC2,
|
||||||
|
MBC5,
|
||||||
Unknown,
|
Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string name;
|
string name;
|
||||||
uint8 cgbflag;
|
uint8 cgbflag;
|
||||||
uint8 sgbflag;
|
uint8 sgbflag;
|
||||||
|
|
||||||
Mapper mapper;
|
Mapper mapper;
|
||||||
bool ram;
|
bool ram;
|
||||||
bool battery;
|
bool battery;
|
||||||
bool rtc;
|
bool rtc;
|
||||||
|
bool rumble;
|
||||||
|
|
||||||
unsigned romsize;
|
unsigned romsize;
|
||||||
unsigned ramsize;
|
unsigned ramsize;
|
||||||
@@ -39,7 +44,6 @@ struct Cartridge : property<Cartridge> {
|
|||||||
void ram_write(unsigned addr, uint8 data);
|
void ram_write(unsigned addr, uint8 data);
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
|
|
||||||
Cartridge();
|
Cartridge();
|
||||||
~Cartridge();
|
~Cartridge();
|
||||||
|
@@ -11,7 +11,4 @@ void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
|
|||||||
void Cartridge::MBC0::power() {
|
void Cartridge::MBC0::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::MBC0::reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -2,5 +2,4 @@ struct MBC0 : MMIO {
|
|||||||
uint8 mmio_read(uint16 addr);
|
uint8 mmio_read(uint16 addr);
|
||||||
void mmio_write(uint16 addr, uint8 data);
|
void mmio_write(uint16 addr, uint8 data);
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
} mbc0;
|
} mbc0;
|
||||||
|
@@ -47,9 +47,6 @@ void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::MBC1::power() {
|
void Cartridge::MBC1::power() {
|
||||||
}
|
|
||||||
|
|
||||||
void Cartridge::MBC1::reset() {
|
|
||||||
ram_enable = false;
|
ram_enable = false;
|
||||||
rom_select = 0x01;
|
rom_select = 0x01;
|
||||||
ram_select = 0x00;
|
ram_select = 0x00;
|
||||||
|
@@ -10,5 +10,4 @@ struct MBC1 : MMIO {
|
|||||||
uint8 mmio_read(uint16 addr);
|
uint8 mmio_read(uint16 addr);
|
||||||
void mmio_write(uint16 addr, uint8 data);
|
void mmio_write(uint16 addr, uint8 data);
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
} mbc1;
|
} mbc1;
|
||||||
|
55
gameboy/cartridge/mbc2/mbc2.cpp
Executable file
55
gameboy/cartridge/mbc2/mbc2.cpp
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifdef CARTRIDGE_CPP
|
||||||
|
|
||||||
|
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
||||||
|
if(addr >= 0x0000 && addr <= 0x3fff) {
|
||||||
|
return cartridge.rom_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x4000 && addr <= 0x7fff) {
|
||||||
|
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xa000 && addr <= 0xa1ff) {
|
||||||
|
if(ram_enable) {
|
||||||
|
uint8 data = cartridge.ram_read(addr & 0x1ff);
|
||||||
|
return (addr & 1) == 0 ? ((data >> 4) & 0x0f) : ((data >> 0) & 0x0f);
|
||||||
|
}
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
|
||||||
|
if(addr >= 0x0000 && addr <= 0x1fff) {
|
||||||
|
if((addr & 0x100) == 0) {
|
||||||
|
ram_enable = (data & 0x0f) == 0x0a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x2000 && addr <= 0x3fff) {
|
||||||
|
if(addr & 0x100) {
|
||||||
|
rom_select = data & 0x0f;
|
||||||
|
if(rom_select == 0) rom_select = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xa000 && addr <= 0xa1ff) {
|
||||||
|
if(ram_enable) {
|
||||||
|
addr &= 511;
|
||||||
|
if((addr & 1) == 0) {
|
||||||
|
cartridge.ram_write(addr, (cartridge.ram_read(addr) & 0x0f) | (data << 4));
|
||||||
|
} else {
|
||||||
|
cartridge.ram_write(addr, (cartridge.ram_read(addr) & 0xf0) | (data << 0));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::MBC2::power() {
|
||||||
|
ram_enable = false;
|
||||||
|
rom_select = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
8
gameboy/cartridge/mbc2/mbc2.hpp
Executable file
8
gameboy/cartridge/mbc2/mbc2.hpp
Executable file
@@ -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;
|
52
gameboy/cartridge/mbc5/mbc5.cpp
Executable file
52
gameboy/cartridge/mbc5/mbc5.cpp
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifdef CARTRIDGE_CPP
|
||||||
|
|
||||||
|
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
||||||
|
if(addr >= 0x0000 && addr <= 0x3fff) {
|
||||||
|
return cartridge.rom_read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x4000 && addr <= 0x7fff) {
|
||||||
|
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xa000 && addr <= 0xbfff) {
|
||||||
|
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 >= 0x0000 && addr <= 0x1fff) {
|
||||||
|
ram_enable = (data & 0x0f) == 0x0a;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x2000 && addr <= 0x2fff) {
|
||||||
|
rom_select = (rom_select & 0x0100) | data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x3000 && addr <= 0x3fff) {
|
||||||
|
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0x4000 && addr <= 0x5fff) {
|
||||||
|
ram_select = data & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xa000 && addr <= 0xbfff) {
|
||||||
|
if(ram_enable) {
|
||||||
|
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartridge::MBC5::power() {
|
||||||
|
ram_enable = false;
|
||||||
|
rom_select = 0x001;
|
||||||
|
ram_select = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
9
gameboy/cartridge/mbc5/mbc5.hpp
Executable file
9
gameboy/cartridge/mbc5/mbc5.hpp
Executable file
@@ -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;
|
@@ -1,4 +1,4 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define CPU_CPP
|
#define CPU_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
@@ -67,9 +67,13 @@ void CPU::interrupt_exec(uint16 pc) {
|
|||||||
op_write(--r[SP], r[PC] >> 0);
|
op_write(--r[SP], r[PC] >> 0);
|
||||||
r[PC] = pc;
|
r[PC] = pc;
|
||||||
op_io();
|
op_io();
|
||||||
|
op_io();
|
||||||
|
op_io();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::power() {
|
void CPU::power() {
|
||||||
|
create(Main, 4 * 1024 * 1024);
|
||||||
|
|
||||||
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
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 = 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 = 0xff00; n <= 0xff0f; n++) bus.mmio[n] = this; //MMIO
|
||||||
@@ -78,15 +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;
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPU::reset() {
|
|
||||||
create(Main, 4 * 1024 * 1024);
|
|
||||||
|
|
||||||
r[PC] = 0x0100;
|
r[PC] = 0x0100;
|
||||||
r[SP] = 0xfffe;
|
r[SP] = 0xfffe;
|
||||||
r[AF] = 0x0000;
|
r[AF] = 0x0100;
|
||||||
r[BC] = 0x0000;
|
r[BC] = 0x0000;
|
||||||
r[DE] = 0x0000;
|
r[DE] = 0x0000;
|
||||||
r[HL] = 0x0000;
|
r[HL] = 0x0000;
|
||||||
|
@@ -63,7 +63,6 @@ struct CPU : Processor, MMIO {
|
|||||||
void interrupt_test();
|
void interrupt_test();
|
||||||
void interrupt_exec(uint16 pc);
|
void interrupt_exec(uint16 pc);
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
CPU();
|
CPU();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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.06";
|
static const char Version[] = "000.07";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ namespace GameBoy {
|
|||||||
inline Processor() : thread(0) {}
|
inline Processor() : thread(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <system/system.hpp>
|
#include <gameboy/system/system.hpp>
|
||||||
#include <scheduler/scheduler.hpp>
|
#include <gameboy/scheduler/scheduler.hpp>
|
||||||
#include <memory/memory.hpp>
|
#include <gameboy/memory/memory.hpp>
|
||||||
#include <cartridge/cartridge.hpp>
|
#include <gameboy/cartridge/cartridge.hpp>
|
||||||
#include <cpu/cpu.hpp>
|
#include <gameboy/cpu/cpu.hpp>
|
||||||
#include <lcd/lcd.hpp>
|
#include <gameboy/lcd/lcd.hpp>
|
||||||
};
|
};
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define LCD_CPP
|
#define LCD_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
@@ -55,93 +55,66 @@ void LCD::frame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LCD::render() {
|
void LCD::render() {
|
||||||
for(unsigned n = 0; n < 160; n++) {
|
for(unsigned n = 0; n < 160; n++) line[n] = 0x00;
|
||||||
line[n].source = Line::Source::None;
|
|
||||||
line[n].output = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(status.display_enable == true) {
|
if(status.display_enable == true) {
|
||||||
if(status.bg_enable == true) render_bg();
|
if(status.bg_enable == true) render_bg();
|
||||||
if(status.obj_enable == true) render_obj();
|
|
||||||
if(status.window_display_enable == true) render_window();
|
if(status.window_display_enable == true) render_window();
|
||||||
|
if(status.obj_enable == true) render_obj();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *output = screen + status.ly * 160;
|
uint8_t *output = screen + status.ly * 160;
|
||||||
for(unsigned n = 0; n < 160; n++) {
|
for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55;
|
||||||
output[n] = (3 - line[n].output) * 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() {
|
void LCD::render_bg() {
|
||||||
unsigned iy = (status.ly + status.scy) & 255;
|
unsigned iy = (status.ly + status.scy) & 255;
|
||||||
unsigned ix = status.scx;
|
unsigned ix = status.scx, tx = ix & 7;
|
||||||
|
uint8 mask = 0x80 >> tx;
|
||||||
|
unsigned data = read_tile(status.bg_tilemap_select, ix, iy), palette;
|
||||||
|
|
||||||
unsigned tmaddr = (status.bg_tilemap_select == 0 ? 0x1800 : 0x1c00);
|
for(unsigned ox = 0; ox < 160; ox++) {
|
||||||
|
palette = ((data & (mask << 0)) ? 1 : 0);
|
||||||
unsigned tx = (ix - 7) & 7;
|
palette |= ((data & (mask << 8)) ? 2 : 0);
|
||||||
uint8 d0 = 0, d1 = 0;
|
mask = (mask >> 1) | (mask << 7);
|
||||||
for(signed ox = -7; ox < 160; ox++) {
|
line[ox] = status.bgp[palette];
|
||||||
if(tx == 0) {
|
|
||||||
unsigned tile = (((iy >> 3) * 32) + (ix >> 3)) & 0x3fff;
|
|
||||||
unsigned tdaddr;
|
|
||||||
if(status.bg_tiledata_select == 0) {
|
|
||||||
tdaddr = 0x1000 + (int8)vram[tmaddr + tile] * 16;
|
|
||||||
} else {
|
|
||||||
tdaddr = 0x0000 + vram[tmaddr + tile] * 16;
|
|
||||||
}
|
|
||||||
tdaddr += (iy & 7) * 2;
|
|
||||||
|
|
||||||
d0 = vram[tdaddr + 0];
|
|
||||||
d1 = vram[tdaddr + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6);
|
|
||||||
d0 <<= 1, d1 <<= 1;
|
|
||||||
|
|
||||||
if(ox >= 0) {
|
|
||||||
line[ox].source = Line::Source::BG;
|
|
||||||
line[ox].output = status.bgp[palette];
|
|
||||||
}
|
|
||||||
|
|
||||||
ix = (ix + 1) & 255;
|
ix = (ix + 1) & 255;
|
||||||
tx = (tx + 1) & 7;
|
tx = (tx + 1) & 7;
|
||||||
|
|
||||||
|
if(tx == 0) data = read_tile(status.bg_tilemap_select, ix, iy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCD::render_window() {
|
void LCD::render_window() {
|
||||||
if(status.wy > status.ly) return;
|
if(status.ly - status.wy >= 144U) return;
|
||||||
unsigned iy = (status.ly + status.wy) & 255;
|
unsigned iy = status.ly - status.wy;
|
||||||
unsigned ix = (status.wx - 7) & 255;
|
unsigned ix = (status.wx - 7) & 255, tx = ix & 7;
|
||||||
|
uint8 mask = 0x80 >> tx;
|
||||||
|
unsigned data = read_tile(status.window_tilemap_select, ix, iy), palette;
|
||||||
|
|
||||||
unsigned tmaddr = (status.window_tilemap_select == 0 ? 0x1800 : 0x1c00);
|
for(unsigned ox = 0; ox < 160; ox++) {
|
||||||
|
palette = ((data & (mask << 0)) ? 1 : 0);
|
||||||
unsigned tx = (ix - 7) & 7;
|
palette |= ((data & (mask << 8)) ? 2 : 0);
|
||||||
uint8 d0 = 0, d1 = 0;
|
mask = (mask >> 1) | (mask << 7);
|
||||||
for(signed ox = -7; ox < 160; ox++) {
|
if(ox - (status.wx - 7) < 160U) line[ox] = status.bgp[palette];
|
||||||
if(tx == 0) {
|
|
||||||
unsigned tile = (((iy >> 3) * 32) + (ix >> 3)) & 0x3fff;
|
|
||||||
unsigned tdaddr;
|
|
||||||
if(status.bg_tiledata_select == 0) {
|
|
||||||
tdaddr = 0x1000 + (int8)vram[tmaddr + tile] * 16;
|
|
||||||
} else {
|
|
||||||
tdaddr = 0x0000 + vram[tmaddr + tile] * 16;
|
|
||||||
}
|
|
||||||
tdaddr += (iy & 7) * 2;
|
|
||||||
|
|
||||||
d0 = vram[tdaddr + 0];
|
|
||||||
d1 = vram[tdaddr + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6);
|
|
||||||
d0 <<= 1, d1 <<= 1;
|
|
||||||
|
|
||||||
if(ox >= 7) {
|
|
||||||
line[ox].source = Line::Source::Window;
|
|
||||||
line[ox].output = status.bgp[palette];
|
|
||||||
}
|
|
||||||
|
|
||||||
ix = (ix + 1) & 255;
|
ix = (ix + 1) & 255;
|
||||||
tx = (tx + 1) & 7;
|
tx = (tx + 1) & 7;
|
||||||
|
|
||||||
|
if(tx == 0) data = read_tile(status.window_tilemap_select, ix, iy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,17 +146,18 @@ void LCD::render_obj() {
|
|||||||
unsigned ox = sx + (tx ^ xflip);
|
unsigned ox = sx + (tx ^ xflip);
|
||||||
|
|
||||||
if(ox <= 159) {
|
if(ox <= 159) {
|
||||||
if((attribute & 0x80) == 1) {
|
if(attribute & 0x80) {
|
||||||
if(line[ox].source == Line::Source::BG && line[ox].output > 0) continue;
|
if(line[ox] > 0) continue;
|
||||||
}
|
}
|
||||||
line[ox].source = Line::Source::OBJ;
|
line[ox] = palette;
|
||||||
line[ox].output = palette;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCD::power() {
|
void LCD::power() {
|
||||||
|
create(Main, 4 * 1024 * 1024);
|
||||||
|
|
||||||
for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
|
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 = 0xff40; n <= 0xff4b; n++) bus.mmio[n] = this; //MMIO
|
||||||
for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
|
for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM
|
||||||
@@ -191,11 +165,6 @@ void LCD::power() {
|
|||||||
for(unsigned n = 0; n < 8192; n++) vram[n] = 0x00;
|
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; n++) oam [n] = 0x00;
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LCD::reset() {
|
|
||||||
create(Main, 4 * 1024 * 1024);
|
|
||||||
for(unsigned n = 0; n < 160 * 144; n++) screen[n] = 0x00;
|
for(unsigned n = 0; n < 160 * 144; n++) screen[n] = 0x00;
|
||||||
|
|
||||||
status.lx = 0;
|
status.lx = 0;
|
||||||
|
@@ -49,11 +49,7 @@ struct LCD : Processor, MMIO {
|
|||||||
uint8 screen[160 * 144];
|
uint8 screen[160 * 144];
|
||||||
uint8 vram[8192];
|
uint8 vram[8192];
|
||||||
uint8 oam[160];
|
uint8 oam[160];
|
||||||
|
uint8 line[160];
|
||||||
struct Line {
|
|
||||||
enum class Source : unsigned { None, BG, OBJ, Window } source;
|
|
||||||
uint8 output;
|
|
||||||
} line[160];
|
|
||||||
|
|
||||||
static void Main();
|
static void Main();
|
||||||
void main();
|
void main();
|
||||||
@@ -61,12 +57,12 @@ struct LCD : Processor, MMIO {
|
|||||||
void scanline();
|
void scanline();
|
||||||
void frame();
|
void frame();
|
||||||
void render();
|
void render();
|
||||||
|
uint16 read_tile(bool select, unsigned x, unsigned y);
|
||||||
void render_bg();
|
void render_bg();
|
||||||
void render_window();
|
void render_window();
|
||||||
void render_obj();
|
void render_obj();
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern LCD lcd;
|
extern LCD lcd;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define MEMORY_CPP
|
#define MEMORY_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define SCHEDULER_CPP
|
#define SCHEDULER_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#define SYSTEM_CPP
|
#define SYSTEM_CPP
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
@@ -17,14 +17,6 @@ void System::power() {
|
|||||||
scheduler.init();
|
scheduler.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::reset() {
|
|
||||||
bus.reset();
|
|
||||||
cartridge.power();
|
|
||||||
cpu.reset();
|
|
||||||
lcd.reset();
|
|
||||||
scheduler.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::run() {
|
void System::run() {
|
||||||
scheduler.enter();
|
scheduler.enter();
|
||||||
}
|
}
|
||||||
|
@@ -8,13 +8,12 @@ class System {
|
|||||||
public:
|
public:
|
||||||
void init(Interface*);
|
void init(Interface*);
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
//private:
|
//private:
|
||||||
Interface *interface;
|
Interface *interface;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <interface/interface.hpp>
|
#include <gameboy/interface/interface.hpp>
|
||||||
|
|
||||||
extern System system;
|
extern System system;
|
||||||
|
@@ -10,7 +10,7 @@ using namespace ruby;
|
|||||||
#include <phoenix/phoenix.hpp>
|
#include <phoenix/phoenix.hpp>
|
||||||
using namespace phoenix;
|
using namespace phoenix;
|
||||||
|
|
||||||
#include <gameboy.hpp>
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
#include "interface.hpp"
|
#include "interface.hpp"
|
||||||
|
|
||||||
|
@@ -9,12 +9,10 @@ void MainWindow::create() {
|
|||||||
systemLoadCartridge.create(system, "Load Cartridge ...");
|
systemLoadCartridge.create(system, "Load Cartridge ...");
|
||||||
systemSeparator1.create(system);
|
systemSeparator1.create(system);
|
||||||
systemPower.create(system, "Power Cycle");
|
systemPower.create(system, "Power Cycle");
|
||||||
systemPower.setEnabled(false);
|
|
||||||
systemReset.create(system, "Reset");
|
|
||||||
systemReset.setEnabled(false);
|
|
||||||
|
|
||||||
settings.create(*this, "Settings");
|
settings.create(*this, "Settings");
|
||||||
//settings.setEnabled(false);
|
settingsVideoSync.create(settings, "Synchronize Video");
|
||||||
|
settingsVideoSync.setChecked(true);
|
||||||
|
|
||||||
tools.create(*this, "Tools");
|
tools.create(*this, "Tools");
|
||||||
//tools.setEnabled(false);
|
//tools.setEnabled(false);
|
||||||
@@ -37,6 +35,14 @@ void MainWindow::create() {
|
|||||||
if(filename != "") utility.loadCartridge(filename);
|
if(filename != "") utility.loadCartridge(filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemPower.onTick = []() {
|
||||||
|
if(GameBoy::cartridge.loaded()) GameBoy::system.power();
|
||||||
|
};
|
||||||
|
|
||||||
|
settingsVideoSync.onTick = []() {
|
||||||
|
video.set(Video::Synchronize, mainWindow.settingsVideoSync.checked());
|
||||||
|
};
|
||||||
|
|
||||||
helpAbout.onTick = []() {
|
helpAbout.onTick = []() {
|
||||||
MessageWindow::information(mainWindow, {
|
MessageWindow::information(mainWindow, {
|
||||||
"bgameboy\n\n",
|
"bgameboy\n\n",
|
||||||
|
@@ -3,9 +3,9 @@ struct MainWindow : Window {
|
|||||||
MenuItem systemLoadCartridge;
|
MenuItem systemLoadCartridge;
|
||||||
MenuSeparator systemSeparator1;
|
MenuSeparator systemSeparator1;
|
||||||
MenuItem systemPower;
|
MenuItem systemPower;
|
||||||
MenuItem systemReset;
|
|
||||||
|
|
||||||
Menu settings;
|
Menu settings;
|
||||||
|
MenuCheckItem settingsVideoSync;
|
||||||
|
|
||||||
Menu tools;
|
Menu tools;
|
||||||
|
|
||||||
|
@@ -22,13 +22,21 @@ void Application::main(int argc, char **argv) {
|
|||||||
mainWindow.setVisible();
|
mainWindow.setVisible();
|
||||||
OS::run();
|
OS::run();
|
||||||
|
|
||||||
|
#if defined(PHOENIX_WINDOWS)
|
||||||
|
video.driver("Direct3D");
|
||||||
|
#else
|
||||||
video.driver("OpenGL");
|
video.driver("OpenGL");
|
||||||
|
#endif
|
||||||
video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle());
|
video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||||
video.set(Video::Synchronize, true);
|
video.set(Video::Synchronize, true);
|
||||||
video.set(Video::Filter, (unsigned)0);
|
video.set(Video::Filter, (unsigned)0);
|
||||||
video.init();
|
video.init();
|
||||||
|
|
||||||
|
#if defined(PHOENIX_WINDOWS)
|
||||||
|
input.driver("RawInput");
|
||||||
|
#else
|
||||||
input.driver("SDL");
|
input.driver("SDL");
|
||||||
|
#endif
|
||||||
input.set(Input::Handle, (uintptr_t)mainWindow.viewport.handle());
|
input.set(Input::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||||
input.init();
|
input.init();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user