Mesen-X/Core/PPU.h

298 lines
6.1 KiB
C
Raw Normal View History

2014-06-14 11:27:55 -04:00
#pragma once
2014-06-14 10:12:10 -04:00
#include "stdafx.h"
2014-06-25 21:52:37 -04:00
#include "Snapshotable.h"
2014-06-15 21:45:36 -04:00
#include "MemoryManager.h"
#include "EmulationSettings.h"
2014-06-14 10:12:10 -04:00
2015-07-21 23:05:27 -04:00
enum class NesModel;
2014-06-14 10:12:10 -04:00
enum PPURegisters
{
Control = 0x00,
Mask = 0x01,
2014-06-14 10:12:10 -04:00
Status = 0x02,
SpriteAddr = 0x03,
SpriteData = 0x04,
ScrollOffsets = 0x05,
VideoMemoryAddr = 0x06,
VideoMemoryData = 0x07,
SpriteDMA = 0x4014,
2014-06-14 10:12:10 -04:00
};
2014-06-14 18:20:56 -04:00
struct PPUControlFlags
{
bool VerticalWrite;
uint16_t SpritePatternAddr;
uint16_t BackgroundPatternAddr;
bool LargeSprites;
bool VBlank;
bool Grayscale;
bool BackgroundMask;
bool SpriteMask;
bool BackgroundEnabled;
bool SpritesEnabled;
bool IntensifyRed;
bool IntensifyGreen;
bool IntensifyBlue;
};
struct PPUStatusFlags
{
bool SpriteOverflow;
bool Sprite0Hit;
bool VerticalBlank;
};
2014-06-14 10:12:10 -04:00
struct PPUState
{
2014-06-14 18:20:56 -04:00
uint8_t Control;
uint8_t Mask;
2014-06-14 10:12:10 -04:00
uint8_t Status;
uint32_t SpriteRamAddr;
2014-06-14 10:12:10 -04:00
uint16_t VideoRamAddr;
2014-06-17 18:16:49 -04:00
uint8_t XScroll;
uint16_t TmpVideoRamAddr;
bool WriteToggle;
uint16_t HighBitShift;
uint16_t LowBitShift;
};
struct TileInfo
{
uint8_t LowByte;
uint8_t HighByte;
uint32_t PaletteOffset;
uint16_t TileAddr; //used by HD ppu
uint8_t OffsetY; //used by HD ppu
};
struct SpriteInfo : TileInfo
{
bool HorizontalMirror;
bool BackgroundPriority;
uint8_t SpriteX;
bool VerticalMirror; //used by HD ppu
2014-06-14 10:12:10 -04:00
};
struct PPUDebugState
{
PPUControlFlags ControlFlags;
PPUStatusFlags StatusFlags;
PPUState State;
int32_t Scanline;
uint32_t Cycle;
uint32_t FrameCount;
};
2014-06-25 21:52:37 -04:00
class PPU : public IMemoryHandler, public Snapshotable
2014-06-14 10:12:10 -04:00
{
protected:
static PPU* Instance;
2014-06-15 21:45:36 -04:00
MemoryManager *_memoryManager;
2014-06-14 11:27:55 -04:00
PPUState _state;
2015-07-21 23:05:27 -04:00
int32_t _scanline;
uint32_t _cycle;
uint32_t _frameCount;
2015-07-21 23:05:27 -04:00
uint8_t _memoryReadBuffer;
uint8_t _paletteRAM[0x20];
uint8_t _spriteRAM[0x100];
2014-06-21 09:00:10 -04:00
uint8_t _secondarySpriteRAM[0x20];
2014-06-14 11:27:55 -04:00
uint16_t *_currentOutputBuffer;
uint16_t *_outputBuffers[2];
2015-07-21 18:18:20 -04:00
2015-07-21 23:05:27 -04:00
NesModel _nesModel;
uint16_t _vblankEnd;
uint16_t _nmiScanline;
2015-07-21 23:05:27 -04:00
2014-06-15 09:35:17 -04:00
PPUControlFlags _flags;
PPUStatusFlags _statusFlags;
2014-06-14 18:20:56 -04:00
uint16_t _intensifyColorBits;
uint8_t _paletteRamMask;
SpriteInfo *_lastSprite; //used by HD ppu
TileInfo _currentTile;
TileInfo _nextTile;
TileInfo _previousTile;
SpriteInfo _spriteTiles[64];
uint32_t _spriteCount;
uint32_t _secondaryOAMAddr;
bool _sprite0Visible;
uint32_t _overflowSpriteAddr;
uint32_t _spriteIndex;
uint8_t _openBus;
int32_t _openBusDecayStamp[8];
uint32_t _ignoreVramRead;
uint16_t _spriteDmaCounter;
uint16_t _spriteDmaAddr;
2015-12-28 20:07:27 -05:00
uint8_t _oamCopybuffer;
bool _spriteInRange;
bool _sprite0Added;
uint8_t _spriteAddrH;
uint8_t _spriteAddrL;
bool _oamCopyDone;
bool _renderingEnabled;
bool _prevRenderingEnabled;
2016-06-12 18:11:31 -04:00
double _cyclesNeeded;
2016-06-25 20:46:54 -04:00
//Used by NSF player for higher performance
bool _simpleMode;
//Used to resolve a race condition when the 2nd write to $2006 occurs at cycle 255 (i.e approx. the same time as the PPU tries to increase Y scrolling)
bool _skipScrollingIncrement;
uint32_t _minimumDrawBgCycle;
uint32_t _minimumDrawSpriteCycle;
uint32_t _minimumDrawSpriteStandardCycle;
2014-06-17 18:16:49 -04:00
void UpdateStatusFlag();
void SetControlRegister(uint8_t value);
void SetMaskRegister(uint8_t value);
2014-06-17 18:16:49 -04:00
bool IsRenderingEnabled();
void SetOpenBus(uint8_t mask, uint8_t value);
uint8_t ApplyOpenBus(uint8_t mask, uint8_t value);
void UpdateVideoRamAddr();
2014-06-17 18:16:49 -04:00
void IncVerticalScrolling();
void IncHorizontalScrolling();
uint16_t GetNameTableAddr();
2014-06-17 18:16:49 -04:00
uint16_t GetAttributeAddr();
__forceinline void ProcessPreVBlankScanline();
2014-06-17 18:16:49 -04:00
void ProcessPrerenderScanline();
__forceinline void ProcessVisibleScanline();
2014-06-14 18:20:56 -04:00
__forceinline void CopyOAMData();
2014-06-17 18:16:49 -04:00
void BeginVBlank();
void TriggerNmi();
2014-06-17 18:16:49 -04:00
void EndVBlank();
2014-06-14 18:20:56 -04:00
void LoadTileInfo();
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite);
void LoadSpriteTileInfo();
void LoadExtraSprites();
void ShiftTileRegisters();
void InitializeShiftRegisters();
void LoadNextTile();
void UpdateMinimumDrawCycles();
__forceinline uint32_t GetPixelColor(uint32_t &paletteOffset);
__forceinline virtual void DrawPixel();
virtual void SendFrame();
2014-06-14 11:27:55 -04:00
PPURegisters GetRegisterID(uint16_t addr)
{
if(addr == 0x4014) {
return PPURegisters::SpriteDMA;
} else {
return (PPURegisters)(addr & 0x07);
}
2014-06-14 10:12:10 -04:00
}
2016-06-25 20:46:54 -04:00
void SetSimpleMode()
{
_simpleMode = true;
}
2014-06-25 21:52:37 -04:00
void StreamState(bool saving);
2014-06-14 11:27:55 -04:00
public:
2015-07-23 23:16:31 -04:00
static const uint32_t ScreenWidth = 256;
static const uint32_t ScreenHeight = 240;
static const uint32_t PixelCount = 256*240;
static const uint32_t OutputBufferSize = 256*240*2;
2014-06-15 21:45:36 -04:00
PPU(MemoryManager *memoryManager);
virtual ~PPU();
2014-06-14 18:20:56 -04:00
void Reset();
void DebugSendFrame();
PPUDebugState GetState();
void SetState(PPUDebugState state);
void GetMemoryRanges(MemoryRanges &ranges)
2014-06-15 21:45:36 -04:00
{
ranges.AddHandler(MemoryOperation::Read, 0x2000, 0x3FFF);
ranges.AddHandler(MemoryOperation::Write, 0x2000, 0x3FFF);
ranges.AddHandler(MemoryOperation::Write, 0x4014);
2014-06-14 11:27:55 -04:00
}
2014-06-14 10:12:10 -04:00
uint8_t ReadPaletteRAM(uint16_t addr);
void WritePaletteRAM(uint16_t addr, uint8_t value);
2014-06-15 21:45:36 -04:00
uint8_t ReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value);
2014-06-14 18:20:56 -04:00
2015-07-21 23:05:27 -04:00
void SetNesModel(NesModel model);
2015-12-26 17:11:00 -05:00
void Exec();
2015-07-21 18:18:20 -04:00
static void ExecStatic();
static uint32_t GetFrameCount()
{
return PPU::Instance->_frameCount;
}
static uint32_t GetFrameCycle()
{
return ((PPU::Instance->_scanline + 1) * 341) + PPU::Instance->_cycle;
}
static PPUControlFlags GetControlFlags()
{
return PPU::Instance->_flags;
}
static uint32_t GetCurrentCycle()
{
return PPU::Instance->_cycle;
}
static int32_t GetCurrentScanline()
{
return PPU::Instance->_scanline;
}
uint8_t* GetSpriteRam()
{
return _spriteRAM;
}
uint8_t* GetSecondarySpriteRam()
{
return _secondarySpriteRAM;
}
static uint32_t GetPixelBrightness(uint8_t x, uint8_t y)
{
//Used by Zapper, gives a rough approximation of the brightness level of the specific pixel
uint16_t pixelData = PPU::Instance->_currentOutputBuffer[y << 8 | x];
uint32_t argbColor = EmulationSettings::GetRgbPalette()[pixelData & 0x3F];
return (argbColor & 0xFF) + ((argbColor >> 8) & 0xFF) + ((argbColor >> 16) & 0xFF);
}
};