From db5e2107b43fc4de32810048ce339fb5a2256005 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 18 Oct 2011 21:05:29 +1100 Subject: [PATCH] Update to v083r02 release. byuu says: It seems impossible to pass blargg's NES ppu_vbl_nmi test 03 and 07 at the same time. Wrote up a description of the problem here: http://nesdev.parodius.com/bbs/viewtopic.php?p=85156#85156 --- bsnes/gameboy/apu/serialization.cpp | 2 + bsnes/gameboy/cpu/serialization.cpp | 2 + bsnes/gameboy/gameboy.hpp | 18 ++++-- bsnes/gameboy/lcd/serialization.cpp | 2 + bsnes/nes/nes.hpp | 9 ++- bsnes/nes/ppu/ppu.cpp | 92 ++++++++++++++--------------- bsnes/nes/ppu/ppu.hpp | 11 ++-- bsnes/nes/ppu/serialization.cpp | 4 +- bsnes/snes/snes.hpp | 13 ++-- bsnes/ui/main.cpp | 4 +- 10 files changed, 90 insertions(+), 67 deletions(-) diff --git a/bsnes/gameboy/apu/serialization.cpp b/bsnes/gameboy/apu/serialization.cpp index c04dc533..34686347 100755 --- a/bsnes/gameboy/apu/serialization.cpp +++ b/bsnes/gameboy/apu/serialization.cpp @@ -1,6 +1,8 @@ #ifdef APU_CPP void APU::serialize(serializer &s) { + Processor::serialize(s); + s.array(mmio_data); s.integer(sequencer_base); s.integer(sequencer_step); diff --git a/bsnes/gameboy/cpu/serialization.cpp b/bsnes/gameboy/cpu/serialization.cpp index 73eab0f6..d096b86f 100755 --- a/bsnes/gameboy/cpu/serialization.cpp +++ b/bsnes/gameboy/cpu/serialization.cpp @@ -1,6 +1,8 @@ #ifdef CPU_CPP void CPU::serialize(serializer &s) { + Processor::serialize(s); + s.array(wram); s.array(hram); diff --git a/bsnes/gameboy/gameboy.hpp b/bsnes/gameboy/gameboy.hpp index f4207e68..4b75abec 100755 --- a/bsnes/gameboy/gameboy.hpp +++ b/bsnes/gameboy/gameboy.hpp @@ -80,14 +80,24 @@ namespace GameBoy { unsigned frequency; int64 clock; - inline void create(void (*entrypoint_)(), unsigned frequency_) { + inline void create(void (*entrypoint)(), unsigned frequency) { if(thread) co_delete(thread); - thread = co_create(65536 * sizeof(void*), entrypoint_); - frequency = frequency_; + thread = co_create(65536 * sizeof(void*), entrypoint); + this->frequency = frequency; clock = 0; } - inline Processor() : thread(nullptr) {} + inline void serialize(serializer &s) { + s.integer(frequency); + s.integer(clock); + } + + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } }; #include diff --git a/bsnes/gameboy/lcd/serialization.cpp b/bsnes/gameboy/lcd/serialization.cpp index a0f21f64..343a6ce0 100755 --- a/bsnes/gameboy/lcd/serialization.cpp +++ b/bsnes/gameboy/lcd/serialization.cpp @@ -1,6 +1,8 @@ #ifdef LCD_CPP void LCD::serialize(serializer &s) { + Processor::serialize(s); + s.integer(status.lx); s.integer(status.wyc); diff --git a/bsnes/nes/nes.hpp b/bsnes/nes/nes.hpp index b01bf7bb..99fca75a 100755 --- a/bsnes/nes/nes.hpp +++ b/bsnes/nes/nes.hpp @@ -80,7 +80,7 @@ namespace NES { struct Processor { cothread_t thread; unsigned frequency; - signed clock; + int64 clock; inline void create(void (*entrypoint)(), unsigned frequency) { if(thread) co_delete(thread); @@ -94,7 +94,12 @@ namespace NES { s.integer(clock); } - inline Processor() : thread(nullptr) {} + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } }; #include diff --git a/bsnes/nes/ppu/ppu.cpp b/bsnes/nes/ppu/ppu.cpp index 1b35b47b..24c6bc89 100755 --- a/bsnes/nes/ppu/ppu.cpp +++ b/bsnes/nes/ppu/ppu.cpp @@ -20,23 +20,28 @@ void PPU::main() { } void PPU::tick() { + if(status.ly == 240 && status.lx == 340) status.nmi_hold = 1; + if(status.ly == 241 && status.lx == 0) status.nmi_flag = status.nmi_hold; + if(status.ly == 241 && status.lx == 2) if(status.nmi_enable && status.nmi_flag) cpu.set_nmi_line(1); + if(status.ly == 261 && status.lx == 0) cpu.set_nmi_line(status.nmi_flag = 0); + if(status.ly == 261 && status.lx == 0) status.sprite_zero_hit = 0; + clock += 4; if(clock >= 0) co_switch(cpu.thread); + + status.lx++; } -void PPU::scanline_edge() { - if(status.ly == 241) { - status.nmi = 1; - if(status.nmi_enable) cpu.set_nmi_line(1); - } - if(status.ly == 261) { - status.nmi = 0; - cpu.set_nmi_line(0); - status.sprite_zero_hit = 0; +void PPU::scanline() { + status.lx = 0; + if(++status.ly == 262) { + status.ly = 0; + frame(); } + cartridge.scanline(status.ly); } -void PPU::frame_edge() { +void PPU::frame() { status.field ^= 1; interface->videoRefresh(buffer); scheduler.exit(Scheduler::ExitReason::FrameEvent); @@ -58,6 +63,9 @@ void PPU::reset() { status.taddr = 0x0000; status.xaddr = 0x00; + status.nmi_hold = 0; + status.nmi_flag = 0; + //$2000 status.nmi_enable = false; status.master_select = 0; @@ -75,18 +83,16 @@ void PPU::reset() { status.grayscale = false; //$2002 - status.nmi = false; status.sprite_zero_hit = false; status.sprite_overflow = false; //$2003 status.oam_addr = 0x00; - memset(buffer, 0, sizeof buffer); - - memset(ciram, 0, sizeof ciram); - memset(cgram, 0, sizeof cgram); - memset(oam, 0, sizeof oam); + for(auto &n : buffer) n = 0; + for(auto &n : ciram ) n = 0; + for(auto &n : cgram ) n = 0; + for(auto &n : oam ) n = 0; } uint8 PPU::read(uint16 addr) { @@ -94,13 +100,13 @@ uint8 PPU::read(uint16 addr) { switch(addr & 7) { case 2: //PPUSTATUS - result |= status.nmi << 7; + result |= status.nmi_flag << 7; result |= status.sprite_zero_hit << 6; result |= status.sprite_overflow << 5; result |= status.mdr & 0x1f; - status.nmi = 0; - cpu.set_nmi_line(0); status.address_latch = 0; + status.nmi_hold = 0; + cpu.set_nmi_line(status.nmi_flag = 0); break; case 4: //OAMDATA result = oam[status.oam_addr]; @@ -133,13 +139,13 @@ void PPU::write(uint16 addr, uint8 data) { switch(addr & 7) { case 0: //PPUCTRL status.nmi_enable = data & 0x80; - cpu.set_nmi_line(status.nmi_enable && status.nmi); status.master_select = data & 0x40; status.sprite_size = data & 0x20; status.bg_addr = (data & 0x10) ? 0x1000 : 0x0000; status.sprite_addr = (data & 0x08) ? 0x1000 : 0x0000; status.vram_increment = (data & 0x04) ? 32 : 1; status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10); + cpu.set_nmi_line(status.nmi_enable && status.nmi_flag); return; case 1: //PPUMASK status.emphasis = data >> 5; @@ -249,15 +255,6 @@ uint8 PPU::chr_load(uint16 addr) { // -void PPU::ly_increment() { - if(++status.ly == 262) { - status.ly = 0; - frame_edge(); - } - scanline_edge(); - cartridge.scanline(status.ly); -} - void PPU::scrollx_increment() { if(raster_enable() == false) return; status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f); @@ -280,10 +277,10 @@ void PPU::scrolly_increment() { // -void PPU::raster_pixel(unsigned x) { +void PPU::raster_pixel() { uint16 *output = buffer + status.ly * 256; - unsigned mask = 0x8000 >> (status.xaddr + x); + unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7)); unsigned palette = 0, object_palette = 0; bool object_priority = 0; palette |= (raster.tiledatalo & mask) ? 1 : 0; @@ -311,7 +308,7 @@ void PPU::raster_pixel(unsigned x) { sprite_palette |= (raster.oam[sprite].tiledatahi & mask) ? 2 : 0; if(sprite_palette == 0) continue; - if(raster.oam[sprite].id == 0 && palette) status.sprite_zero_hit = 1; + if(raster.oam[sprite].id == 0 && palette && status.lx != 255) status.sprite_zero_hit = 1; sprite_palette |= (raster.oam[sprite].attr & 3) << 2; object_priority = raster.oam[sprite].attr & 0x20; @@ -323,7 +320,7 @@ void PPU::raster_pixel(unsigned x) { } if(raster_enable() == false) palette = 0; - output[status.lx++] = (status.emphasis << 6) | cgram_read(palette); + output[status.lx] = (status.emphasis << 6) | cgram_read(palette); } void PPU::raster_sprite() { @@ -349,14 +346,10 @@ void PPU::raster_sprite() { void PPU::raster_scanline() { if((status.ly >= 240 && status.ly <= 260)) { - for(unsigned x = 0; x < 340; x++) tick(); - if(raster_enable() == false || status.field != 1 || status.ly != 240) tick(); - return ly_increment(); + for(unsigned x = 0; x < 341; x++) tick(); + return scanline(); } - signed lx = 0, ly = (status.ly == 261 ? -1 : status.ly); - status.lx = 0; - raster.oam_iterator = 0; raster.oam_counter = 0; @@ -373,36 +366,36 @@ void PPU::raster_scanline() { for(unsigned tile = 0; tile < 32; tile++) { // 0-255 unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff)); unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7); - raster_pixel(0); + raster_pixel(); tick(); - raster_pixel(1); + raster_pixel(); tick(); unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5)); if(scrolly() & 16) attribute >>= 4; if(scrollx() & 16) attribute >>= 2; - raster_pixel(2); + raster_pixel(); tick(); scrollx_increment(); if(tile == 31) scrolly_increment(); - raster_pixel(3); + raster_pixel(); raster_sprite(); tick(); unsigned tiledatalo = chr_load(tileaddr + 0); - raster_pixel(4); + raster_pixel(); tick(); - raster_pixel(5); + raster_pixel(); tick(); unsigned tiledatahi = chr_load(tileaddr + 8); - raster_pixel(6); + raster_pixel(); tick(); - raster_pixel(7); + raster_pixel(); raster_sprite(); tick(); @@ -476,14 +469,15 @@ void PPU::raster_scanline() { tick(); tick(); + bool skip = (raster_enable() && status.field == 1 && status.ly == 261); chr_load(0x2000 | (status.vaddr & 0x0fff)); tick(); tick(); //340 - tick(); + if(skip == false) tick(); - return ly_increment(); + return scanline(); } } diff --git a/bsnes/nes/ppu/ppu.hpp b/bsnes/nes/ppu/ppu.hpp index 9671098f..24ebdcbd 100755 --- a/bsnes/nes/ppu/ppu.hpp +++ b/bsnes/nes/ppu/ppu.hpp @@ -3,8 +3,8 @@ struct PPU : Processor { void main(); void tick(); - void scanline_edge(); - void frame_edge(); + void scanline(); + void frame(); void power(); void reset(); @@ -26,11 +26,10 @@ struct PPU : Processor { uint8 chr_load(uint16 addr); - void ly_increment(); void scrollx_increment(); void scrolly_increment(); - void raster_pixel(unsigned x); + void raster_pixel(); void raster_sprite(); void raster_scanline(); @@ -51,6 +50,9 @@ struct PPU : Processor { uint15 taddr; uint8 xaddr; + bool nmi_hold; + bool nmi_flag; + //$2000 bool nmi_enable; bool master_select; @@ -68,7 +70,6 @@ struct PPU : Processor { bool grayscale; //$2002 - bool nmi; bool sprite_zero_hit; bool sprite_overflow; diff --git a/bsnes/nes/ppu/serialization.cpp b/bsnes/nes/ppu/serialization.cpp index 786075f3..db4cee1b 100755 --- a/bsnes/nes/ppu/serialization.cpp +++ b/bsnes/nes/ppu/serialization.cpp @@ -15,6 +15,9 @@ void PPU::serialize(serializer &s) { s.integer(status.taddr); s.integer(status.xaddr); + s.integer(status.nmi_hold); + s.integer(status.nmi_flag); + s.integer(status.nmi_enable); s.integer(status.master_select); s.integer(status.sprite_size); @@ -29,7 +32,6 @@ void PPU::serialize(serializer &s) { s.integer(status.bg_edge_enable); s.integer(status.grayscale); - s.integer(status.nmi); s.integer(status.sprite_zero_hit); s.integer(status.sprite_overflow); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 66ea5b21..91196f9e 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -106,10 +106,10 @@ namespace SNES { unsigned frequency; int64 clock; - inline void create(void (*entrypoint_)(), unsigned frequency_) { + inline void create(void (*entrypoint)(), unsigned frequency) { if(thread) co_delete(thread); - thread = co_create(65536 * sizeof(void*), entrypoint_); - frequency = frequency_; + thread = co_create(65536 * sizeof(void*), entrypoint); + this->frequency = frequency; clock = 0; } @@ -118,7 +118,12 @@ namespace SNES { s.integer(clock); } - inline Processor() : thread(nullptr) {} + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } }; struct ChipDebugger { diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 9a4fbf04..c45fb289 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -27,6 +27,8 @@ void Application::run() { } Application::Application(int argc, char **argv) { + title = "bsnes v083.02"; + application = this; quit = false; pause = false; @@ -49,8 +51,6 @@ Application::Application(int argc, char **argv) { inputManager = new InputManager; utility = new Utility; - title = "bsnes v083.01"; - string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, "; normalFont = { fontFamily, "8" }; boldFont = { fontFamily, "8, Bold" };