mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-23 17:19:39 +00:00
PPU: Fixed reset state (started at cycle 1 instead of 0) + adjusted reset sync values (improves read2004 result).
+Simplified PPU code for a small performance boost (+3-6%)
This commit is contained in:
parent
fa39dcbc80
commit
c477d75b66
@ -105,9 +105,10 @@ void CPU::Reset(bool softReset, NesModel model)
|
||||
}
|
||||
|
||||
//The CPU takes some cycles before starting its execution after a reset/power up
|
||||
for(int i = 0; i < (model == NesModel::NTSC ? 12 : 15); i++) {
|
||||
PPU::ExecStatic();
|
||||
for(int i = 0; i < (model == NesModel::NTSC ? 28 : 30); i++) {
|
||||
PPU::RunOneCycle();
|
||||
}
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
APU::ExecStatic();
|
||||
}
|
||||
|
93
Core/PPU.cpp
93
Core/PPU.cpp
@ -71,6 +71,7 @@ void PPU::Reset()
|
||||
_prevRenderingEnabled = false;
|
||||
_cyclesNeeded = 0.0;
|
||||
|
||||
memset(_hasSprite, 0, sizeof(_hasSprite));
|
||||
memset(_spriteTiles, 0, sizeof(SpriteInfo));
|
||||
_spriteCount = 0;
|
||||
_secondaryOAMAddr = 0;
|
||||
@ -81,8 +82,10 @@ void PPU::Reset()
|
||||
memset(_openBusDecayStamp, 0, sizeof(_openBusDecayStamp));
|
||||
_ignoreVramRead = 0;
|
||||
|
||||
_scanline = 0;
|
||||
_cycle = 0;
|
||||
//First execution will be cycle 0, scanline 0
|
||||
_scanline = -1;
|
||||
_cycle = 340;
|
||||
|
||||
_frameCount = 1;
|
||||
_memoryReadBuffer = 0;
|
||||
|
||||
@ -515,9 +518,8 @@ void PPU::LoadTileInfo()
|
||||
_previousTile = _currentTile;
|
||||
_currentTile = _nextTile;
|
||||
|
||||
if(_cycle > 1 && _cycle < 256) {
|
||||
LoadNextTile();
|
||||
}
|
||||
_state.LowBitShift |= _nextTile.LowByte;
|
||||
_state.HighBitShift |= _nextTile.HighByte;
|
||||
|
||||
uint8_t tileIndex = _mapper->ReadVRAM(GetNameTableAddr());
|
||||
_nextTile.TileAddr = (tileIndex << 4) | (_state.VideoRamAddr >> 12) | _flags.BackgroundPatternAddr;
|
||||
@ -537,9 +539,6 @@ void PPU::LoadTileInfo()
|
||||
|
||||
case 5:
|
||||
_nextTile.HighByte = _mapper->ReadVRAM(_nextTile.TileAddr + 8);
|
||||
if(_cycle == 334) {
|
||||
InitializeShiftRegisters();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -632,29 +631,17 @@ void PPU::LoadSpriteTileInfo()
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::LoadNextTile()
|
||||
{
|
||||
_state.LowBitShift |= _nextTile.LowByte;
|
||||
_state.HighBitShift |= _nextTile.HighByte;
|
||||
}
|
||||
|
||||
void PPU::InitializeShiftRegisters()
|
||||
{
|
||||
_state.LowBitShift = (_currentTile.LowByte << 8) | _nextTile.LowByte;
|
||||
_state.HighBitShift = (_currentTile.HighByte << 8) | _nextTile.HighByte;
|
||||
}
|
||||
|
||||
void PPU::ShiftTileRegisters()
|
||||
{
|
||||
_state.LowBitShift <<= 1;
|
||||
_state.HighBitShift <<= 1;
|
||||
}
|
||||
|
||||
uint32_t PPU::GetPixelColor()
|
||||
uint8_t PPU::GetPixelColor()
|
||||
{
|
||||
uint8_t offset = _state.XScroll;
|
||||
uint32_t backgroundColor = 0;
|
||||
uint32_t spriteBgColor = 0;
|
||||
uint8_t backgroundColor = 0;
|
||||
uint8_t spriteBgColor = 0;
|
||||
|
||||
if(_cycle > _minimumDrawBgCycle) {
|
||||
//BackgroundMask = false: Hide background in leftmost 8 pixels of screen
|
||||
@ -670,7 +657,7 @@ uint32_t PPU::GetPixelColor()
|
||||
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
|
||||
if(shift >= 0 && shift < 8) {
|
||||
_lastSprite = &_spriteTiles[i];
|
||||
uint32_t spriteColor;
|
||||
uint8_t spriteColor;
|
||||
if(_spriteTiles[i].HorizontalMirror) {
|
||||
spriteColor = ((_lastSprite->LowByte >> shift) & 0x01) | ((_lastSprite->HighByte >> shift) & 0x01) << 1;
|
||||
} else {
|
||||
@ -746,7 +733,8 @@ void PPU::UpdateGrayscaleAndIntensifyBits()
|
||||
|
||||
void PPU::ProcessScanline()
|
||||
{
|
||||
if(_cycle > 0 && _cycle <= 256) {
|
||||
//Only called for cycle 1+
|
||||
if(_cycle <= 256) {
|
||||
LoadTileInfo();
|
||||
|
||||
if(_prevRenderingEnabled && (_cycle & 0x07) == 0) {
|
||||
@ -763,6 +751,7 @@ void PPU::ProcessScanline()
|
||||
//"Secondary OAM clear and sprite evaluation do not occur on the pre-render line"
|
||||
ProcessSpriteEvaluation();
|
||||
} else if(_cycle < 9) {
|
||||
//Pre-render scanline logic
|
||||
if(_cycle == 1) {
|
||||
_statusFlags.VerticalBlank = false;
|
||||
}
|
||||
@ -814,6 +803,8 @@ void PPU::ProcessScanline()
|
||||
);
|
||||
}
|
||||
} else if(_prevRenderingEnabled && (_cycle == 328 || _cycle == 336)) {
|
||||
_state.LowBitShift <<= 8;
|
||||
_state.HighBitShift <<= 8;
|
||||
IncHorizontalScrolling();
|
||||
}
|
||||
} else if(_cycle == 337 || _cycle == 339) {
|
||||
@ -826,9 +817,6 @@ void PPU::ProcessScanline()
|
||||
_cycle = 340;
|
||||
}
|
||||
}
|
||||
} else if(_scanline == -1 && _cycle == 0) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -994,10 +982,8 @@ void PPU::SendFrame()
|
||||
|
||||
void PPU::BeginVBlank()
|
||||
{
|
||||
if(_cycle == 0) {
|
||||
SendFrame();
|
||||
TriggerNmi();
|
||||
}
|
||||
SendFrame();
|
||||
TriggerNmi();
|
||||
}
|
||||
|
||||
void PPU::TriggerNmi()
|
||||
@ -1011,31 +997,40 @@ void PPU::TriggerNmi()
|
||||
void PPU::Exec()
|
||||
{
|
||||
if(_cycle > 339) {
|
||||
_cycle = -1;
|
||||
_cycle = 0;
|
||||
if(++_scanline > _vblankEnd) {
|
||||
_lastUpdatedPixel = -1;
|
||||
_frameCount++;
|
||||
_scanline = -1;
|
||||
UpdateMinimumDrawCycles();
|
||||
}
|
||||
}
|
||||
_cycle++;
|
||||
|
||||
Debugger::ProcessPpuCycle();
|
||||
Debugger::ProcessPpuCycle();
|
||||
|
||||
if(_scanline < 240) {
|
||||
ProcessScanline();
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_nesModel == NesModel::PAL && _scanline >= _palSpriteEvalScanline) {
|
||||
//"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it
|
||||
//from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen
|
||||
//even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else
|
||||
//it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES."
|
||||
if(_cycle > 0 && _cycle <= 256) {
|
||||
ProcessSpriteEvaluation();
|
||||
} else if(_cycle >= 257 && _cycle < 320) {
|
||||
_state.SpriteRamAddr = 0;
|
||||
//Cycle = 0
|
||||
if(_scanline == -1) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
}
|
||||
} else {
|
||||
//Cycle > 0
|
||||
_cycle++;
|
||||
|
||||
Debugger::ProcessPpuCycle();
|
||||
if(_scanline < 240) {
|
||||
ProcessScanline();
|
||||
} else if(_nesModel == NesModel::PAL && _scanline >= _palSpriteEvalScanline) {
|
||||
//"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it
|
||||
//from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen
|
||||
//even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else
|
||||
//it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES."
|
||||
if(_cycle <= 256) {
|
||||
ProcessSpriteEvaluation();
|
||||
} else if(_cycle >= 257 && _cycle < 320) {
|
||||
_state.SpriteRamAddr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,15 +126,13 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
void LoadSpriteTileInfo();
|
||||
void LoadExtraSprites();
|
||||
__forceinline void ShiftTileRegisters();
|
||||
void InitializeShiftRegisters();
|
||||
void LoadNextTile();
|
||||
|
||||
__forceinline uint8_t ReadSpriteRam(uint8_t addr);
|
||||
__forceinline void WriteSpriteRam(uint8_t addr, uint8_t value);
|
||||
|
||||
void UpdateMinimumDrawCycles();
|
||||
|
||||
__forceinline uint32_t GetPixelColor();
|
||||
__forceinline uint8_t GetPixelColor();
|
||||
__forceinline virtual void DrawPixel();
|
||||
void UpdateGrayscaleAndIntensifyBits();
|
||||
virtual void SendFrame();
|
||||
@ -182,6 +180,11 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
|
||||
void Exec();
|
||||
static void ExecStatic();
|
||||
|
||||
static void RunOneCycle()
|
||||
{
|
||||
Instance->Exec();
|
||||
}
|
||||
|
||||
static uint32_t GetFrameCount()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user