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
This commit is contained in:
Tim Allen 2011-10-18 21:05:29 +11:00
parent 13ac6104e3
commit db5e2107b4
10 changed files with 90 additions and 67 deletions

View File

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

View File

@ -1,6 +1,8 @@
#ifdef CPU_CPP
void CPU::serialize(serializer &s) {
Processor::serialize(s);
s.array(wram);
s.array(hram);

View File

@ -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 <gameboy/memory/memory.hpp>

View File

@ -1,6 +1,8 @@
#ifdef LCD_CPP
void LCD::serialize(serializer &s) {
Processor::serialize(s);
s.integer(status.lx);
s.integer(status.wyc);

View File

@ -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 <nes/system/system.hpp>

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

@ -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" };