mirror of https://github.com/bsnes-emu/bsnes.git
Update to release v000r05.
byuu says: Fixed all of the previously mentioned problems by myself and Jonas Quinn. Fixed up JOYP and hooked up JOYP interrupts, they work on JOYP writes as well if your selection makes the low four bits change to != 0xF. Added basic sprite emulation, very very very lousy but it works for Tetris. Fixed DAA, fuck that opcode. Fixes blargg's CPU tests 1 and 11 (for some odd reason.) Only test 2 is failing, on the "EI" test. Maybe it relies on STAT interrupts? Did some other stuff. Tetris is now 100% fully playable. But that renderer is an abomination. Soooooo simplistic and missing so many edge cases. But holy shit, a fully playable commercial game in three days. I would have killed to have made that progress when I started on bsnes.
This commit is contained in:
parent
2330ed6e8c
commit
42a9f9cfa4
|
@ -61,6 +61,10 @@ 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]);
|
||||
}
|
||||
|
@ -101,6 +105,7 @@ void CPU::op_ld_nn_sp() {
|
|||
|
||||
void CPU::op_ld_sp_hl() {
|
||||
r[SP] = r[HL];
|
||||
op_io();
|
||||
}
|
||||
|
||||
template<unsigned x> void CPU::op_push_rr() {
|
||||
|
@ -137,7 +142,7 @@ void CPU::opi_adc_a(uint8 x) {
|
|||
r.f.z = (uint8)rh == 0;
|
||||
r.f.n = 0;
|
||||
r.f.h = rl > 0x0f;
|
||||
r.f.c = rh > 0x0f;
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void CPU::op_adc_a_r() { opi_adc_a(r[x]); }
|
||||
|
@ -214,7 +219,7 @@ void CPU::opi_cp_a(uint8 x) {
|
|||
r.f.z = (uint8)rh == 0;
|
||||
r.f.n = 1;
|
||||
r.f.h = rl > 0x0f;
|
||||
r.f.c = rh > 0x0f;
|
||||
r.f.c = rh > 0xff;
|
||||
}
|
||||
|
||||
template<unsigned x> void CPU::op_cp_a_r() { opi_cp_a(r[x]); }
|
||||
|
@ -252,10 +257,10 @@ void CPU::op_dec_hl() {
|
|||
}
|
||||
|
||||
void CPU::op_daa() {
|
||||
signed a = r[A];
|
||||
uint16 a = r[A];
|
||||
if(r.f.n == 0) {
|
||||
if(r.f.h || (a & 0x0f) > 0x09) a += 0x06;
|
||||
if(r.f.c || (a & 0xff) > 0x9f) a += 0x60;
|
||||
if(r.f.c || (a ) > 0x9f) a += 0x60;
|
||||
} else {
|
||||
if(r.f.h) {
|
||||
a -= 0x06;
|
||||
|
@ -266,7 +271,7 @@ void CPU::op_daa() {
|
|||
r[A] = a;
|
||||
r.f.z = r[A] == 0;
|
||||
r.f.h = 0;
|
||||
r.f.c = a & 0x100;
|
||||
r.f.c |= a & 0x100;
|
||||
}
|
||||
|
||||
void CPU::op_cpl() {
|
||||
|
@ -278,6 +283,7 @@ void CPU::op_cpl() {
|
|||
//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;
|
||||
|
@ -287,14 +293,18 @@ template<unsigned x> void CPU::op_add_hl_rr() {
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -304,6 +314,7 @@ void CPU::op_add_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;
|
||||
|
|
|
@ -18,6 +18,7 @@ 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();
|
||||
|
|
|
@ -270,7 +270,7 @@ string CPU::disassemble_opcode(uint16 pc) {
|
|||
case 0xef: return { "rst $0028" };
|
||||
case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" };
|
||||
case 0xf1: return { "pop af" };
|
||||
case 0xf2: return { "xx" };
|
||||
case 0xf2: return { "ld a,($ff00+c)" };
|
||||
case 0xf3: return { "di" };
|
||||
case 0xf4: return { "xx" };
|
||||
case 0xf5: return { "push af" };
|
||||
|
|
|
@ -127,7 +127,7 @@ void CPU::initialize_opcode_table() {
|
|||
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<E>;
|
||||
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>;
|
||||
|
@ -243,7 +243,7 @@ void CPU::initialize_opcode_table() {
|
|||
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_xx;
|
||||
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>;
|
||||
|
|
|
@ -88,6 +88,7 @@ void CPU::reset() {
|
|||
|
||||
status.p15 = 0;
|
||||
status.p14 = 0;
|
||||
status.joyp = 0;
|
||||
|
||||
status.div = 0;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ struct CPU : Processor, MMIO {
|
|||
//$ff00 JOYP
|
||||
bool p15;
|
||||
bool p14;
|
||||
uint8 joyp;
|
||||
|
||||
//$ff04 DIV
|
||||
uint8 div;
|
||||
|
|
|
@ -1,30 +1,33 @@
|
|||
#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 == 0) status.joyp &= button ^ 0x0f;
|
||||
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
|
||||
if(status.joyp != 0x0f) status.interrupt_request_joypad = 1;
|
||||
}
|
||||
|
||||
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
|
||||
unsigned keys = 0x0f;
|
||||
|
||||
if(status.p15 == 0 && status.p14 == 1) {
|
||||
keys = !system.interface->input_poll((unsigned)Input::Down) << 3;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::Up) << 2;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::Left) << 1;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::Right) << 0;
|
||||
}
|
||||
|
||||
if(status.p15 == 1 && status.p14 == 0) {
|
||||
keys = !system.interface->input_poll((unsigned)Input::Start) << 3;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::Select) << 2;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::B) << 1;
|
||||
keys |= !system.interface->input_poll((unsigned)Input::A) << 0;
|
||||
}
|
||||
|
||||
return (status.p15 << 5)
|
||||
| (status.p14 << 4)
|
||||
| (keys << 0);
|
||||
| (status.joyp << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff04) { //DIV
|
||||
|
@ -71,6 +74,7 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
|
|||
if(addr == 0xff00) { //JOYP
|
||||
status.p15 = data & 0x20;
|
||||
status.p14 = data & 0x10;
|
||||
mmio_joyp_poll();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.04";
|
||||
static const char Version[] = "000.05";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ void LCD::scanline() {
|
|||
void LCD::frame() {
|
||||
system.interface->video_refresh(screen);
|
||||
system.interface->input_poll();
|
||||
cpu.mmio_joyp_poll();
|
||||
|
||||
status.ly = 0;
|
||||
scheduler.exit();
|
||||
|
@ -68,6 +69,32 @@ void LCD::render() {
|
|||
*output++ = (3 - status.bgp[palette]) * 0x55;
|
||||
}
|
||||
}
|
||||
|
||||
output = screen + status.ly * 160;
|
||||
for(unsigned s = 0; s < 40; s++) {
|
||||
unsigned sy = oam[(s << 2) + 0] - 9;
|
||||
unsigned sx = oam[(s << 2) + 1] - 8;
|
||||
unsigned tile = oam[(s << 2) + 2];
|
||||
unsigned attribute = oam[(s << 2) + 3];
|
||||
|
||||
sy -= status.ly;
|
||||
if(sy >= 8) continue;
|
||||
if(attribute & 0x40||1) sy ^= 7;
|
||||
|
||||
unsigned addr = tile * 16 + sy * 2;
|
||||
|
||||
uint8 d0 = vram[addr + 0];
|
||||
uint8 d1 = vram[addr + 1];
|
||||
unsigned xflip = attribute & 0x20 ? -7 : 0;
|
||||
|
||||
for(unsigned x = 0; x < 8; x++) {
|
||||
uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6);
|
||||
d0 <<= 1, d1 <<= 1;
|
||||
if(palette == 0) continue;
|
||||
palette = status.obp[(bool)(attribute & 0x10)][palette];
|
||||
output[sx + (x ^ xflip)] = (3 - palette) * 0x55;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::power() {
|
||||
|
@ -113,8 +140,8 @@ void LCD::reset() {
|
|||
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
status.bgp[n] = n;
|
||||
status.obp0[n] = n;
|
||||
status.obp1[n] = n;
|
||||
status.obp[0][n] = n;
|
||||
status.obp[1][n] = n;
|
||||
}
|
||||
|
||||
status.wy = 0;
|
||||
|
|
|
@ -38,10 +38,8 @@ struct LCD : Processor, MMIO {
|
|||
uint8 bgp[4];
|
||||
|
||||
//$ff48 OBP0
|
||||
uint8 obp0[4];
|
||||
|
||||
//$ff49 OBP1
|
||||
uint8 obp1[4];
|
||||
uint8 obp[2][4];
|
||||
|
||||
//$ff4a WY
|
||||
uint8 wy;
|
||||
|
|
|
@ -48,17 +48,17 @@ uint8 LCD::mmio_read(uint16 addr) {
|
|||
}
|
||||
|
||||
if(addr == 0xff48) { //OBP0
|
||||
return (status.obp0[3] << 6)
|
||||
| (status.obp0[2] << 4)
|
||||
| (status.obp0[1] << 2)
|
||||
| (status.obp0[0] << 0);
|
||||
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.obp1[3] << 6)
|
||||
| (status.obp1[2] << 4)
|
||||
| (status.obp1[1] << 2)
|
||||
| (status.obp1[0] << 0);
|
||||
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
|
||||
|
@ -117,7 +117,7 @@ void LCD::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
|
||||
if(addr == 0xff46) { //DMA
|
||||
//TODO
|
||||
for(unsigned n = 0x00; n <= 0x9f; n++) bus.write(0xfe00 + n, bus.read((data << 8) + n));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -130,18 +130,18 @@ void LCD::mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
|
||||
if(addr == 0xff48) { //OBP0
|
||||
status.obp0[3] = (data >> 6) & 3;
|
||||
status.obp0[2] = (data >> 4) & 3;
|
||||
status.obp0[1] = (data >> 2) & 3;
|
||||
status.obp0[0] = (data >> 0) & 3;
|
||||
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.obp1[3] = (data >> 6) & 3;
|
||||
status.obp1[2] = (data >> 4) & 3;
|
||||
status.obp1[1] = (data >> 2) & 3;
|
||||
status.obp1[0] = (data >> 0) & 3;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ void Application::main(int argc, char **argv) {
|
|||
|
||||
video.driver("OpenGL");
|
||||
video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||
video.set(Video::Synchronize, false);
|
||||
video.set(Video::Synchronize, true);
|
||||
video.set(Video::Filter, (unsigned)0);
|
||||
video.init();
|
||||
|
||||
|
|
Loading…
Reference in New Issue