Mesen/Core/PPU.h

261 lines
5.8 KiB
C++

#pragma once
#include "stdafx.h"
#include "Snapshotable.h"
#include "EmulationSettings.h"
#include "Types.h"
#include "DebuggerTypes.h"
#include "IMemoryHandler.h"
enum class NesModel;
class BaseMapper;
class ControlManager;
class Console;
enum PPURegisters
{
Control = 0x00,
Mask = 0x01,
Status = 0x02,
SpriteAddr = 0x03,
SpriteData = 0x04,
ScrollOffsets = 0x05,
VideoMemoryAddr = 0x06,
VideoMemoryData = 0x07,
SpriteDMA = 0x4014,
};
class PPU : public IMemoryHandler, public Snapshotable
{
protected:
shared_ptr<Console> _console;
EmulationSettings* _settings;
PPUState _state;
int32_t _scanline;
uint32_t _cycle;
uint32_t _frameCount;
uint64_t _masterClock;
uint8_t _masterClockDivider;
uint8_t _memoryReadBuffer;
uint8_t _paletteRAM[0x20];
uint8_t _spriteRAM[0x100];
uint8_t _secondarySpriteRAM[0x20];
bool _hasSprite[257];
uint16_t *_currentOutputBuffer;
uint16_t *_outputBuffers[2];
NesModel _nesModel;
uint16_t _standardVblankEnd;
uint16_t _standardNmiScanline;
uint16_t _vblankEnd;
uint16_t _nmiScanline;
uint16_t _palSpriteEvalScanline;
PPUControlFlags _flags;
PPUStatusFlags _statusFlags;
uint16_t _intensifyColorBits;
uint8_t _paletteRamMask;
int32_t _lastUpdatedPixel;
SpriteInfo *_lastSprite; //used by HD ppu
uint16_t _ppuBusAddress;
TileInfo _currentTile;
TileInfo _nextTile;
TileInfo _previousTile;
SpriteInfo _spriteTiles[64];
uint32_t _spriteCount;
uint32_t _secondaryOAMAddr;
bool _sprite0Visible;
uint8_t _firstVisibleSpriteAddr;
uint8_t _lastVisibleSpriteAddr;
uint32_t _spriteIndex;
uint8_t _openBus;
int32_t _openBusDecayStamp[8];
uint32_t _ignoreVramRead;
uint8_t _oamCopybuffer;
bool _spriteInRange;
bool _sprite0Added;
uint8_t _spriteAddrH;
uint8_t _spriteAddrL;
bool _oamCopyDone;
uint8_t _overflowBugCounter;
bool _needStateUpdate;
bool _renderingEnabled;
bool _prevRenderingEnabled;
bool _preventVblFlag;
uint16_t _updateVramAddr;
uint8_t _updateVramAddrDelay;
uint32_t _minimumDrawBgCycle;
uint32_t _minimumDrawSpriteCycle;
uint32_t _minimumDrawSpriteStandardCycle;
uint64_t _oamDecayCycles[0x40];
bool _enableOamDecay;
bool _corruptOamRow[32];
void UpdateStatusFlag();
void SetControlRegister(uint8_t value);
void SetMaskRegister(uint8_t value);
bool IsRenderingEnabled();
void ProcessTmpAddrScrollGlitch(uint16_t normalAddr, uint16_t value, uint16_t mask);
void SetOpenBus(uint8_t mask, uint8_t value);
uint8_t ApplyOpenBus(uint8_t mask, uint8_t value);
void ProcessStatusRegOpenBus(uint8_t & openBusMask, uint8_t & returnValue);
void UpdateVideoRamAddr();
void IncVerticalScrolling();
void IncHorizontalScrolling();
uint16_t GetNameTableAddr();
uint16_t GetAttributeAddr();
__forceinline void ProcessScanline();
__forceinline void ProcessSpriteEvaluation();
void BeginVBlank();
void TriggerNmi();
void LoadTileInfo();
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite);
void LoadSpriteTileInfo();
void LoadExtraSprites();
__forceinline void ShiftTileRegisters();
__forceinline uint8_t ReadSpriteRam(uint8_t addr);
__forceinline void WriteSpriteRam(uint8_t addr, uint8_t value);
void SetOamCorruptionFlags();
void ProcessOamCorruption();
void UpdateMinimumDrawCycles();
uint8_t GetPixelColor();
__forceinline virtual void DrawPixel();
void UpdateGrayscaleAndIntensifyBits();
virtual void SendFrame();
void UpdateState();
void UpdateApuStatus();
PPURegisters GetRegisterID(uint16_t addr)
{
if(addr == 0x4014) {
return PPURegisters::SpriteDMA;
} else {
return (PPURegisters)(addr & 0x07);
}
}
__forceinline void SetBusAddress(uint16_t addr);
__forceinline uint8_t ReadVram(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead);
__forceinline void WriteVram(uint16_t addr, uint8_t value);
void StreamState(bool saving) override;
public:
static constexpr int32_t ScreenWidth = 256;
static constexpr int32_t ScreenHeight = 240;
static constexpr int32_t PixelCount = 256*240;
static constexpr int32_t OutputBufferSize = 256*240*2;
static constexpr int32_t OamDecayCycleCount = 3000;
PPU(shared_ptr<Console> console);
virtual ~PPU();
void Reset();
void DebugSendFrame();
uint16_t* GetScreenBuffer(bool previousBuffer);
void DebugCopyOutputBuffer(uint16_t *target);
void DebugUpdateFrameBuffer(bool toGrayscale);
void GetState(PPUDebugState &state);
void SetState(PPUDebugState &state);
void GetMemoryRanges(MemoryRanges &ranges) override
{
ranges.AddHandler(MemoryOperation::Read, 0x2000, 0x3FFF);
ranges.AddHandler(MemoryOperation::Write, 0x2000, 0x3FFF);
ranges.AddHandler(MemoryOperation::Write, 0x4014);
}
uint8_t ReadPaletteRAM(uint16_t addr);
void WritePaletteRAM(uint16_t addr, uint8_t value);
uint8_t ReadRAM(uint16_t addr) override;
uint8_t PeekRAM(uint16_t addr) override;
void WriteRAM(uint16_t addr, uint8_t value) override;
void SetNesModel(NesModel model);
double GetOverclockRate();
void Exec();
__forceinline void Run(uint64_t runTo);
uint32_t GetFrameCount()
{
return _frameCount;
}
uint32_t GetFrameCycle()
{
return ((_scanline + 1) * 341) + _cycle;
}
PPUControlFlags GetControlFlags()
{
return _flags;
}
uint32_t GetCurrentCycle()
{
return _cycle;
}
int32_t GetCurrentScanline()
{
return _scanline;
}
uint8_t* GetSpriteRam();
uint8_t* GetSecondarySpriteRam()
{
return _secondarySpriteRAM;
}
uint32_t GetPixelBrightness(uint8_t x, uint8_t y);
uint16_t GetCurrentBgColor();
uint16_t GetPixel(uint8_t x, uint8_t y)
{
return _currentOutputBuffer[y << 8 | x];
}
};
void PPU::Run(uint64_t runTo)
{
while(_masterClock + _masterClockDivider <= runTo) {
Exec();
_masterClock += _masterClockDivider;
}
}