Rewrote sprite evaluation logic to match wiki - fixes "sprite overflow - 3.timing" test

This commit is contained in:
Souryo 2016-01-03 11:44:20 -05:00
parent 64b2856d7c
commit b135f9f4e4
2 changed files with 67 additions and 49 deletions

View file

@ -645,10 +645,13 @@ void PPU::CopyOAMData()
_secondarySpriteRAM[_cycle >> 1] = _oamCopybuffer; _secondarySpriteRAM[_cycle >> 1] = _oamCopybuffer;
} else { } else {
if(_cycle == 65) { if(_cycle == 65) {
_overflowCounter = 0;
_sprite0Added = false; _sprite0Added = false;
_writeOAMData = false; _spriteInRange = false;
_secondaryOAMAddr = 0; _secondaryOAMAddr = 0;
_oamCopyDone = false;
_spriteAddrH = (_state.SpriteRamAddr >> 2) & 0x3F;
_spriteAddrL = _state.SpriteRamAddr & 0x03;
} else if(_cycle == 256) { } else if(_cycle == 256) {
_sprite0Visible = _sprite0Added; _sprite0Visible = _sprite0Added;
_spriteCount = (_secondaryOAMAddr >> 2); _spriteCount = (_secondaryOAMAddr >> 2);
@ -656,52 +659,63 @@ void PPU::CopyOAMData()
if(_cycle & 0x01) { if(_cycle & 0x01) {
//Read a byte from the primary OAM on odd cycles //Read a byte from the primary OAM on odd cycles
_oamCopybuffer = _spriteRAM[_state.SpriteRamAddr & 0xFF]; _oamCopybuffer = _spriteRAM[(_spriteAddrH << 2) + _spriteAddrL];
_state.SpriteRamAddr++;
} else { } else {
if(!_writeOAMData && _scanline >= _oamCopybuffer && _scanline < _oamCopybuffer + (_flags.LargeSprites ? 16 : 8) && _state.SpriteRamAddr < 0x100) { if(_oamCopyDone) {
_writeOAMData = true; _spriteAddrH = (_spriteAddrH + 1) & 0x3F;
}
if(_secondaryOAMAddr < 0x20) {
//Copy 1 byte to secondary OAM
_secondarySpriteRAM[_secondaryOAMAddr] = _oamCopybuffer;
if(_writeOAMData) {
_secondaryOAMAddr++;
if(_state.SpriteRamAddr == 0x01) {
_sprite0Added = true;
}
if((_secondaryOAMAddr & 0x03) == 0) {
//Done copying
_writeOAMData = false;
}
} else {
_state.SpriteRamAddr += 3;
}
} else { } else {
//8 sprites have been found, check next sprite for overflow + emulate PPU bug if(!_spriteInRange && _scanline >= _oamCopybuffer && _scanline < _oamCopybuffer + (_flags.LargeSprites ? 16 : 8)) {
//Based on: http://forums.nesdev.com/viewtopic.php?p=85431#p85431 _spriteInRange = true;
//Behavior matches: http://forums.nesdev.com/viewtopic.php?p=1387#p1387 }
if(!_statusFlags.SpriteOverflow) {
if(_writeOAMData) { if(_secondaryOAMAddr < 0x20) {
//Sprite is visible, consider this to be an overflow //Copy 1 byte to secondary OAM
_statusFlags.SpriteOverflow = true; _secondarySpriteRAM[_secondaryOAMAddr] = _oamCopybuffer;
_overflowCounter = 3;
} else if((_state.SpriteRamAddr & 0x3) != 0) { if(_spriteInRange) {
//Sprite isn't on this scanline, trigger sprite evaluation bug _spriteAddrL++;
_state.SpriteRamAddr += 4; _secondaryOAMAddr++;
}
} else { if(_spriteAddrH == 0) {
if(_overflowCounter != 0) { _sprite0Added = true;
_overflowCounter--; }
if(_overflowCounter == 0) {
_state.SpriteRamAddr = (_state.SpriteRamAddr + 3) & 0x0FFC; if(_spriteAddrL == 4) {
//Done copying all 4 bytes
_spriteInRange = false;
_spriteAddrL = 0;
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
if(_spriteAddrH == 0) {
_oamCopyDone = true;
}
} }
} else { } else {
_state.SpriteRamAddr = (_state.SpriteRamAddr + 4) & 0x0FFC; //Nothing to copy, skip to next sprite
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
if(_spriteAddrH == 0) {
_oamCopyDone = true;
}
}
} else {
//8 sprites have been found, check next sprite for overflow + emulate PPU bug
if(_spriteInRange) {
//Sprite is visible, consider this to be an overflow
_statusFlags.SpriteOverflow = true;
_spriteAddrL = (_spriteAddrL + 1) & 0x03;
if(_spriteAddrL == 4) {
_spriteInRange = false;
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
_oamCopyDone = true;
_spriteAddrL = 0;
}
} else {
//Sprite isn't on this scanline, trigger sprite evaluation bug - increment both H & L at the same time
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
_spriteAddrL = (_spriteAddrL + 1) & 0x03;
if(_spriteAddrH == 0) {
_oamCopyDone = true;
}
} }
} }
} }
@ -837,9 +851,11 @@ void PPU::StreamState(bool saving)
Stream<bool>(_sprite0Visible); Stream<bool>(_sprite0Visible);
Stream<uint8_t>(_oamCopybuffer); Stream<uint8_t>(_oamCopybuffer);
Stream<bool>(_writeOAMData); Stream<bool>(_spriteInRange);
Stream<uint32_t>(_overflowCounter);
Stream<bool>(_sprite0Added); Stream<bool>(_sprite0Added);
Stream<uint8_t>(_spriteAddrH);
Stream<uint8_t>(_spriteAddrL);
Stream<bool>(_oamCopyDone);
Stream<NesModel>(_nesModel); Stream<NesModel>(_nesModel);

View file

@ -138,10 +138,12 @@ class PPU : public IMemoryHandler, public Snapshotable
uint16_t _spriteDmaAddr = 0; uint16_t _spriteDmaAddr = 0;
uint8_t _oamCopybuffer; uint8_t _oamCopybuffer;
bool _writeOAMData; bool _spriteInRange;
uint32_t _overflowCounter;
bool _sprite0Added; bool _sprite0Added;
uint8_t _spriteAddrH;
uint8_t _spriteAddrL;
bool _oamCopyDone;
void UpdateStatusFlag(); void UpdateStatusFlag();
void SetControlRegister(uint8_t value); void SetControlRegister(uint8_t value);