Improved timing, passes some more VBL/NMI tests
This commit is contained in:
parent
616546ae5b
commit
6e1742393d
4 changed files with 66 additions and 24 deletions
35
Core/CPU.h
35
Core/CPU.h
|
@ -152,7 +152,7 @@ private:
|
|||
uint8_t SP() { return _state.SP; }
|
||||
void SetSP(uint8_t value) { _state.SP = value; }
|
||||
uint8_t PS() { return _state.PS; }
|
||||
void SetPS(uint8_t value) { _state.PS = (value & 0xDF) | PSFlags::Reserved; }
|
||||
void SetPS(uint8_t value) { _state.PS = (value & 0xCF) | PSFlags::Reserved; }
|
||||
uint16_t PC() { return _state.PC; }
|
||||
void SetPC(uint16_t value) { _state.PC = value; }
|
||||
|
||||
|
@ -609,12 +609,20 @@ private:
|
|||
|
||||
void BRK() {
|
||||
Push((uint16_t)(PC() + 1));
|
||||
|
||||
uint8_t flags = PS() | PSFlags::Break;
|
||||
Push((uint8_t)flags);
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
uint8_t flags = PS() | PSFlags::Break;
|
||||
if(CPU::NMIFlag) {
|
||||
Push((uint8_t)flags);
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
|
||||
SetPC(MemoryReadWord(CPU::NMIVector));
|
||||
} else {
|
||||
|
||||
Push((uint8_t)flags);
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
}
|
||||
}
|
||||
|
||||
void NMI() {
|
||||
|
@ -626,9 +634,17 @@ private:
|
|||
|
||||
void IRQ() {
|
||||
Push((uint16_t)(PC()));
|
||||
Push((uint8_t)PS());
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
|
||||
if(CPU::NMIFlag) {
|
||||
Push((uint8_t)PS());
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
|
||||
SetPC(MemoryReadWord(CPU::NMIVector));
|
||||
} else {
|
||||
Push((uint8_t)PS());
|
||||
SetFlags(PSFlags::Interrupt);
|
||||
SetPC(MemoryReadWord(CPU::IRQVector));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -652,6 +668,7 @@ public:
|
|||
CPU::CycleCount += cycles;
|
||||
}
|
||||
static void SetNMIFlag() { CPU::NMIFlag = true; }
|
||||
static void ClearNMIFlag() { CPU::NMIFlag = false; }
|
||||
static void SetIRQSource(IRQSource source)
|
||||
{
|
||||
CPU::IRQFlag |= (int)source;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "PPU.h"
|
||||
|
||||
MemoryManager::MemoryManager(shared_ptr<BaseMapper> mapper)
|
||||
{
|
||||
|
@ -103,21 +104,25 @@ void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
|
|||
|
||||
uint8_t MemoryManager::Read(uint16_t addr)
|
||||
{
|
||||
uint8_t value;
|
||||
PPU::ExecStatic(3);
|
||||
if(addr <= 0x1FFF) {
|
||||
return _internalRAM[addr & 0x07FF];
|
||||
value = _internalRAM[addr & 0x07FF];
|
||||
} else if(addr <= 0x401F) {
|
||||
return ReadRegister(addr);
|
||||
value = ReadRegister(addr);
|
||||
} else if(addr <= 0x5FFF) {
|
||||
return _expansionRAM[addr & 0x1FFF];
|
||||
value = _expansionRAM[addr & 0x1FFF];
|
||||
} else if(addr <= 0x7FFF) {
|
||||
return _SRAM[addr & 0x1FFF];
|
||||
value = _SRAM[addr & 0x1FFF];
|
||||
} else {
|
||||
return ReadRegister(addr);
|
||||
value = ReadRegister(addr);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void MemoryManager::Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
PPU::ExecStatic(3);
|
||||
if(addr <= 0x1FFF) {
|
||||
_internalRAM[addr & 0x07FF] = value;
|
||||
} else if(addr <= 0x401F) {
|
||||
|
|
31
Core/PPU.cpp
31
Core/PPU.cpp
|
@ -211,10 +211,14 @@ void PPU::SetControlRegister(uint8_t value)
|
|||
_flags.BackgroundPatternAddr = ((_state.Control & 0x10) == 0x10) ? 0x1000 : 0x0000;
|
||||
_flags.LargeSprites = (_state.Control & 0x20) == 0x20;
|
||||
|
||||
//"By toggling NMI_output ($2000 bit 7) during vertical blank without reading $2002, a program can cause /NMI to be pulled low multiple times, causing multiple NMIs to be generated."
|
||||
bool originalVBlank = _flags.VBlank;
|
||||
_flags.VBlank = (_state.Control & 0x80) == 0x80;
|
||||
|
||||
if(!originalVBlank && _flags.VBlank && _statusFlags.VerticalBlank) {
|
||||
CPU::SetNMIFlag();
|
||||
} else if(_scanline == 241 && _cycle < 3 && !_flags.VBlank) {
|
||||
CPU::ClearNMIFlag();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,8 +242,14 @@ void PPU::UpdateStatusFlag()
|
|||
((uint8_t)_statusFlags.VerticalBlank << 7);
|
||||
_statusFlags.VerticalBlank = false;
|
||||
|
||||
if(_scanline == 241 && _cycle == 0) {
|
||||
_doNotSetVBFlag = true;
|
||||
if(_scanline == 241) {
|
||||
if(_cycle < 3) {
|
||||
CPU::ClearNMIFlag();
|
||||
|
||||
if(_cycle == 0) {
|
||||
_doNotSetVBFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,7 +483,7 @@ void PPU::ProcessPrerenderScanline()
|
|||
{
|
||||
ProcessPreVBlankScanline();
|
||||
|
||||
if(_cycle == 1) {
|
||||
if(_cycle == 0) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
_statusFlags.VerticalBlank = false;
|
||||
|
@ -486,8 +496,8 @@ void PPU::ProcessPrerenderScanline()
|
|||
//copy vertical scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BE0) | (_state.TmpVideoRamAddr & 0x7BE0);
|
||||
}
|
||||
} else if(_cycle == 339 && _flags.BackgroundEnabled && (_frameCount % 2 == 1)) {
|
||||
//Skip a cycle for odd frames, if background drawing is enabled
|
||||
} else if(_cycle == 339 && IsRenderingEnabled() && (_frameCount % 2 == 1)) {
|
||||
//"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340)
|
||||
_cycle = -1;
|
||||
_scanline = 0;
|
||||
} else if(_cycle == 321 || _cycle == 329) {
|
||||
|
@ -616,7 +626,7 @@ void PPU::CopyOAMData()
|
|||
|
||||
void PPU::BeginVBlank()
|
||||
{
|
||||
if(_cycle == 1) {
|
||||
if(_cycle == 0) {
|
||||
if(!_doNotSetVBFlag) {
|
||||
_statusFlags.VerticalBlank = true;
|
||||
if(_flags.VBlank) {
|
||||
|
@ -634,10 +644,15 @@ void PPU::EndVBlank()
|
|||
}
|
||||
}
|
||||
|
||||
void PPU::Exec()
|
||||
void PPU::Exec(uint32_t extraCycles)
|
||||
{
|
||||
uint64_t equivalentCycleCount = CPU::GetCycleCount() * 3;
|
||||
uint32_t gap = (uint32_t)(equivalentCycleCount - _cycleCount);
|
||||
int32_t gap = (int32_t)((int64_t)equivalentCycleCount - (int64_t)_cycleCount);
|
||||
if(gap < 0) {
|
||||
gap = 0;
|
||||
}
|
||||
gap += extraCycles;
|
||||
|
||||
_cycleCount += gap;
|
||||
while(gap > 0) {
|
||||
if(_scanline == -1) {
|
||||
|
|
|
@ -88,7 +88,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
uint32_t _frameCount = 0;
|
||||
uint64_t _cycleCount = 0;
|
||||
uint8_t _memoryReadBuffer = 0;
|
||||
|
||||
|
||||
uint8_t _paletteRAM[0x100];
|
||||
|
||||
uint8_t _spriteRAM[0x100];
|
||||
|
@ -178,7 +178,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
uint8_t ReadRAM(uint16_t addr);
|
||||
void WriteRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
void Exec();
|
||||
void Exec(uint32_t extraCycles = 0);
|
||||
|
||||
static void RegisterVideoDevice(IVideoDevice *videoDevice)
|
||||
{
|
||||
|
@ -209,4 +209,9 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
{
|
||||
return PPU::Instance->_scanline;
|
||||
}
|
||||
|
||||
static void ExecStatic(uint32_t cycles)
|
||||
{
|
||||
PPU::Instance->Exec(cycles);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue