mirror of https://github.com/bsnes-emu/bsnes.git
Update to release v000r08.
byuu says: Changelog: - rewrote sprite rendering, grabs first ten sprites, draws them in revere order of a: X-index, b: OAM appearance order - simplified tile decoding to use less variables - added MBC3 emulation (for now, RTC is always enabled) - STOP can be broken via joypad IF, this may not be correct though (it may trigger even without P10-13 being modified) - cleaned up all MBC emulation to use masks instead of ranges - MBC2 uses 512-byte table now, ignores high 4-bits. Easier this way I guess - tools menu temporarily has a console tracer enable option - some other stuff No real visible improvements :(
This commit is contained in:
parent
afdb3c4d20
commit
a7ffbd784b
|
@ -6,6 +6,7 @@ namespace GameBoy {
|
|||
#include "mbc0/mbc0.cpp"
|
||||
#include "mbc1/mbc1.cpp"
|
||||
#include "mbc2/mbc2.cpp"
|
||||
#include "mbc3/mbc3.cpp"
|
||||
#include "mbc5/mbc5.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
|
@ -34,6 +35,13 @@ void Cartridge::load(uint8_t *data, unsigned size) {
|
|||
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 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;
|
||||
|
@ -64,7 +72,7 @@ void Cartridge::load(uint8_t *data, unsigned size) {
|
|||
case 0x03: info.ramsize = 32 * 1024; break;
|
||||
}
|
||||
|
||||
if(info.mapper == Mapper::MBC2) info.ramsize = 256; //512 x 4-bit
|
||||
if(info.mapper == Mapper::MBC2) info.ramsize = 512; //512 x 4-bit
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
|
||||
|
@ -105,6 +113,7 @@ void Cartridge::power() {
|
|||
mbc0.power();
|
||||
mbc1.power();
|
||||
mbc2.power();
|
||||
mbc3.power();
|
||||
mbc5.power();
|
||||
|
||||
MMIO *mapper = 0;
|
||||
|
@ -112,6 +121,7 @@ void Cartridge::power() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@ struct Cartridge : property<Cartridge> {
|
|||
#include "mbc0/mbc0.hpp"
|
||||
#include "mbc1/mbc1.hpp"
|
||||
#include "mbc2/mbc2.hpp"
|
||||
#include "mbc3/mbc3.hpp"
|
||||
#include "mbc5/mbc5.hpp"
|
||||
|
||||
enum Mapper : unsigned {
|
||||
MBC0,
|
||||
MBC1,
|
||||
MBC2,
|
||||
MBC3,
|
||||
MBC5,
|
||||
Unknown,
|
||||
};
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
|
||||
if(addr >= 0x0000 && addr <= 0x7fff) return cartridge.rom_read(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() {
|
||||
|
|
|
@ -1,48 +1,62 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
||||
if(addr >= 0x0000 && addr <= 0x3fff) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if(addr >= 0x4000 && addr <= 0x7fff) {
|
||||
return cartridge.rom_read(rom_bank | (addr & 0x3fff));
|
||||
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 >= 0xa000 && addr <= 0xbfff) {
|
||||
if(ram_enable) return cartridge.ram_read(ram_bank | (addr & 0x1fff));
|
||||
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 >= 0x0000 && addr <= 0x1fff) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x2000 && addr <= 0x3fff) {
|
||||
rom_select = data & 0x1f;
|
||||
if(rom_select == 0) rom_select = 1;
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x4000 && addr <= 0x5fff) {
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
ram_select = data & 0x03;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x6000 && addr <= 0x7fff) {
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
mode_select = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode_select == 0) {
|
||||
rom_bank = (ram_select << 19) | (rom_select << 14);
|
||||
ram_bank = 0x00;
|
||||
} else {
|
||||
rom_bank = (rom_select << 14);
|
||||
ram_bank = (ram_select << 13);
|
||||
}
|
||||
|
||||
if(addr >= 0xa000 && addr <= 0xbfff) {
|
||||
if(ram_enable) cartridge.ram_write(ram_bank | (addr & 0x1fff), data);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,9 +65,6 @@ void Cartridge::MBC1::power() {
|
|||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
mode_select = 0;
|
||||
|
||||
rom_bank = 0x4000;
|
||||
ram_bank = 0x0000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,9 +4,6 @@ struct MBC1 : MMIO {
|
|||
uint8 ram_select; //4000-5fff
|
||||
bool mode_select; //6000-7fff
|
||||
|
||||
unsigned rom_bank;
|
||||
unsigned ram_bank;
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
||||
if(addr >= 0x0000 && addr <= 0x3fff) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if(addr >= 0x4000 && addr <= 0x7fff) {
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
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);
|
||||
}
|
||||
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
|
||||
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
|
@ -21,29 +18,19 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
|||
}
|
||||
|
||||
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 & 0xe100) == 0x0000) { //0000-1fff [d8=0]
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x2000 && addr <= 0x3fff) {
|
||||
if(addr & 0x100) {
|
||||
rom_select = data & 0x0f;
|
||||
if(rom_select == 0) rom_select = 1;
|
||||
}
|
||||
if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1]
|
||||
rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
|
||||
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 << 13) | (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;
|
|
@ -1,18 +1,16 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
||||
if(addr >= 0x0000 && addr <= 0x3fff) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if(addr >= 0x4000 && addr <= 0x7fff) {
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
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));
|
||||
}
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
|
@ -20,26 +18,29 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
|||
}
|
||||
|
||||
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0x0000 && addr <= 0x1fff) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x2000 && addr <= 0x2fff) {
|
||||
if((addr & 0xf000) == 0x2000) { //2000-2fff
|
||||
rom_select = (rom_select & 0x0100) | data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x3000 && addr <= 0x3fff) {
|
||||
if((addr & 0xf000) == 0x3000) { //3000-3fff
|
||||
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x4000 && addr <= 0x5fff) {
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
ram_select = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0xa000 && addr <= 0xbfff) {
|
||||
if(ram_enable) {
|
||||
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
}
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ void CPU::Main() {
|
|||
|
||||
void CPU::main() {
|
||||
while(true) {
|
||||
//print(disassemble(r[PC]), "\n");
|
||||
if(trace) print(disassemble(r[PC]), "\n");
|
||||
interrupt_test();
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
(this->*opcode_table[opcode])();
|
||||
|
@ -27,7 +27,7 @@ void CPU::interrupt_raise(CPU::Interrupt id) {
|
|||
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; break;
|
||||
case Interrupt::Joypad: status.interrupt_request_joypad = 1; status.stop = false; break;
|
||||
}
|
||||
status.halt = false;
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ void CPU::power() {
|
|||
r[DE] = 0x0000;
|
||||
r[HL] = 0x0000;
|
||||
|
||||
status.clock = 0;
|
||||
status.halt = false;
|
||||
status.stop = false;
|
||||
|
||||
|
@ -124,7 +125,7 @@ void CPU::power() {
|
|||
status.interrupt_enable_vblank = 0;
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
CPU::CPU() : trace(false) {
|
||||
initialize_opcode_table();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ struct CPU : Processor, MMIO {
|
|||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
bool trace;
|
||||
|
||||
enum class Interrupt : unsigned {
|
||||
Vblank,
|
||||
Stat,
|
||||
|
@ -12,6 +14,7 @@ struct CPU : Processor, MMIO {
|
|||
};
|
||||
|
||||
struct Status {
|
||||
unsigned clock;
|
||||
bool halt;
|
||||
bool stop;
|
||||
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
#include "opcode.cpp"
|
||||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
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();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.07";
|
||||
static const char Version[] = "000.08";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,13 +82,11 @@ uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {
|
|||
void LCD::render_bg() {
|
||||
unsigned iy = (status.ly + status.scy) & 255;
|
||||
unsigned ix = status.scx, tx = ix & 7;
|
||||
uint8 mask = 0x80 >> tx;
|
||||
unsigned data = read_tile(status.bg_tilemap_select, ix, iy), palette;
|
||||
unsigned data = read_tile(status.bg_tilemap_select, ix, iy);
|
||||
|
||||
for(unsigned ox = 0; ox < 160; ox++) {
|
||||
palette = ((data & (mask << 0)) ? 1 : 0);
|
||||
palette |= ((data & (mask << 8)) ? 2 : 0);
|
||||
mask = (mask >> 1) | (mask << 7);
|
||||
uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0)
|
||||
| ((data & (0x8000 >> tx)) ? 2 : 0);
|
||||
line[ox] = status.bgp[palette];
|
||||
|
||||
ix = (ix + 1) & 255;
|
||||
|
@ -102,13 +100,11 @@ 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;
|
||||
uint8 mask = 0x80 >> tx;
|
||||
unsigned data = read_tile(status.window_tilemap_select, ix, iy), palette;
|
||||
unsigned data = read_tile(status.window_tilemap_select, ix, iy);
|
||||
|
||||
for(unsigned ox = 0; ox < 160; ox++) {
|
||||
palette = ((data & (mask << 0)) ? 1 : 0);
|
||||
palette |= ((data & (mask << 8)) ? 2 : 0);
|
||||
mask = (mask >> 1) | (mask << 7);
|
||||
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;
|
||||
|
@ -121,25 +117,53 @@ void LCD::render_window() {
|
|||
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;
|
||||
unsigned tile = oam[(s << 2) + 2];
|
||||
unsigned attribute = oam[(s << 2) + 3];
|
||||
|
||||
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 * 16 + sy * 2;
|
||||
|
||||
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) >> 7) + ((d1 & 0x80) >> 6);
|
||||
d0 <<= 1, d1 <<= 1;
|
||||
uint8 palette = ((d0 & (0x80 >> tx)) ? 1 : 0)
|
||||
| ((d1 & (0x80 >> tx)) ? 2 : 0);
|
||||
if(palette == 0) continue;
|
||||
|
||||
palette = status.obp[(bool)(attribute & 0x10)][palette];
|
||||
|
|
|
@ -15,7 +15,7 @@ void MainWindow::create() {
|
|||
settingsVideoSync.setChecked(true);
|
||||
|
||||
tools.create(*this, "Tools");
|
||||
//tools.setEnabled(false);
|
||||
toolsTraceCPU.create(tools, "Trace CPU");
|
||||
|
||||
help.create(*this, "Help");
|
||||
helpAbout.create(help, "About ...");
|
||||
|
@ -43,6 +43,10 @@ void MainWindow::create() {
|
|||
video.set(Video::Synchronize, mainWindow.settingsVideoSync.checked());
|
||||
};
|
||||
|
||||
toolsTraceCPU.onTick = []() {
|
||||
GameBoy::cpu.trace = mainWindow.toolsTraceCPU.checked();
|
||||
};
|
||||
|
||||
helpAbout.onTick = []() {
|
||||
MessageWindow::information(mainWindow, {
|
||||
"bgameboy\n\n",
|
||||
|
|
|
@ -8,6 +8,7 @@ struct MainWindow : Window {
|
|||
MenuCheckItem settingsVideoSync;
|
||||
|
||||
Menu tools;
|
||||
MenuCheckItem toolsTraceCPU;
|
||||
|
||||
Menu help;
|
||||
MenuItem helpAbout;
|
||||
|
|
Loading…
Reference in New Issue