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"
2016-02-05 23:14:27 -05:00
# 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 ,
2014-06-22 00:37:45 -04:00
Mask = 0x01 ,
2014-06-14 10:12:10 -04:00
Status = 0x02 ,
SpriteAddr = 0x03 ,
SpriteData = 0x04 ,
ScrollOffsets = 0x05 ,
VideoMemoryAddr = 0x06 ,
2014-06-20 21:48:55 -04:00
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 ;
2014-06-22 00:37:45 -04:00
uint8_t Mask ;
2014-06-14 10:12:10 -04:00
uint8_t Status ;
2014-06-20 21:48:55 -04:00
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 ;
2014-06-18 22:54:23 -04:00
uint16_t HighBitShift ;
uint16_t LowBitShift ;
} ;
struct TileInfo
2014-06-21 12:42:40 -04:00
{
uint8_t LowByte ;
uint8_t HighByte ;
2014-06-22 16:22:10 -04:00
uint32_t PaletteOffset ;
2015-08-14 21:50:14 -04:00
uint16_t TileAddr ; //used by HD ppu
uint8_t OffsetY ; //used by HD ppu
2014-06-21 12:42:40 -04:00
} ;
2015-08-14 21:50:14 -04:00
struct SpriteInfo : TileInfo
2014-06-18 22:54:23 -04:00
{
2014-06-20 21:48:55 -04:00
bool HorizontalMirror ;
2014-06-21 12:42:40 -04:00
bool BackgroundPriority ;
2015-08-14 21:50:14 -04:00
uint8_t SpriteX ;
2015-08-15 10:40:27 -04:00
bool VerticalMirror ; //used by HD ppu
2014-06-14 10:12:10 -04:00
} ;
2015-07-01 23:17:14 -04:00
struct PPUDebugState
{
PPUControlFlags ControlFlags ;
PPUStatusFlags StatusFlags ;
PPUState State ;
int32_t Scanline ;
uint32_t Cycle ;
} ;
2014-06-25 21:52:37 -04:00
class PPU : public IMemoryHandler , public Snapshotable
2014-06-14 10:12:10 -04:00
{
2015-08-14 21:50:14 -04:00
protected :
2014-06-25 17:30:35 -04:00
static PPU * Instance ;
2014-06-18 22:54:23 -04:00
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 ;
2016-01-02 20:36:22 -05:00
uint32_t _frameCount ;
2015-07-21 23:05:27 -04:00
uint8_t _memoryReadBuffer ;
2015-08-05 21:43:53 -04:00
uint8_t _paletteRAM [ 0x20 ] ;
2014-06-20 22:31:48 -04:00
2014-06-15 11:25:29 -04:00
uint8_t _spriteRAM [ 0x100 ] ;
2014-06-21 09:00:10 -04:00
uint8_t _secondarySpriteRAM [ 0x20 ] ;
2014-06-14 11:27:55 -04:00
2015-08-30 21:04:21 -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 ;
2016-06-21 18:58:22 -04:00
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
2015-07-22 22:08:28 -04:00
uint16_t _intensifyColorBits ;
uint8_t _paletteRamMask ;
2015-08-14 21:50:14 -04:00
SpriteInfo * _lastSprite ; //used by HD ppu
2014-06-18 22:54:23 -04:00
TileInfo _currentTile ;
TileInfo _nextTile ;
2014-06-19 19:58:15 -04:00
TileInfo _previousTile ;
2014-06-20 21:48:55 -04:00
2016-01-14 22:20:50 -05:00
SpriteInfo _spriteTiles [ 64 ] ;
2014-06-22 01:54:35 -04:00
uint32_t _spriteCount = 0 ;
uint32_t _secondaryOAMAddr = 0 ;
2014-06-21 12:42:40 -04:00
bool _sprite0Visible = false ;
2014-07-01 18:05:54 -04:00
2016-01-14 22:20:50 -05:00
uint32_t _overflowSpriteAddr = 0 ;
2015-12-29 13:23:38 -05:00
uint32_t _spriteIndex = 0 ;
2016-01-02 20:36:22 -05:00
uint8_t _openBus = 0 ;
int32_t _openBusDecayStamp [ 8 ] ;
2016-01-03 17:20:18 -05:00
uint32_t _ignoreVramRead = 0 ;
2016-01-02 20:36:22 -05:00
2015-12-28 20:07:27 -05:00
uint16_t _spriteDmaCounter = 0 ;
uint16_t _spriteDmaAddr = 0 ;
2014-07-01 18:05:54 -04:00
uint8_t _oamCopybuffer ;
2016-01-03 11:44:20 -05:00
bool _spriteInRange ;
2014-07-01 18:05:54 -04:00
bool _sprite0Added ;
2016-01-03 11:44:20 -05:00
uint8_t _spriteAddrH ;
uint8_t _spriteAddrL ;
bool _oamCopyDone ;
2016-01-11 17:18:01 -05:00
bool _renderingEnabled ;
2016-02-14 13:57:47 -05:00
bool _prevRenderingEnabled ;
2016-05-31 17:12:43 -04:00
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 ;
2016-05-31 17:12:43 -04:00
//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 ;
2016-01-03 11:44:20 -05:00
2014-06-17 18:16:49 -04:00
void UpdateStatusFlag ( ) ;
2014-06-22 00:37:45 -04:00
void SetControlRegister ( uint8_t value ) ;
void SetMaskRegister ( uint8_t value ) ;
2014-06-17 18:16:49 -04:00
bool IsRenderingEnabled ( ) ;
2016-01-02 20:36:22 -05:00
void SetOpenBus ( uint8_t mask , uint8_t value ) ;
uint8_t ApplyOpenBus ( uint8_t mask , uint8_t value ) ;
2014-06-22 00:37:45 -04:00
void UpdateVideoRamAddr ( ) ;
2014-06-17 18:16:49 -04:00
void IncVerticalScrolling ( ) ;
void IncHorizontalScrolling ( ) ;
2014-06-19 19:58:15 -04:00
uint16_t GetNameTableAddr ( ) ;
2014-06-17 18:16:49 -04:00
uint16_t GetAttributeAddr ( ) ;
2016-06-06 23:09:22 -04:00
__forceinline void ProcessPreVBlankScanline ( ) ;
2014-06-17 18:16:49 -04:00
void ProcessPrerenderScanline ( ) ;
2016-06-06 23:09:22 -04:00
__forceinline void ProcessVisibleScanline ( ) ;
2014-06-14 18:20:56 -04:00
2016-06-06 23:09:22 -04:00
__forceinline void CopyOAMData ( ) ;
2014-06-20 21:48:55 -04:00
2014-06-17 18:16:49 -04:00
void BeginVBlank ( ) ;
2016-01-30 19:33:32 -05:00
void TriggerNmi ( ) ;
2014-06-17 18:16:49 -04:00
void EndVBlank ( ) ;
2014-06-14 18:20:56 -04:00
2014-06-20 22:31:48 -04:00
void WritePaletteRAM ( uint16_t addr , uint8_t value ) ;
2016-01-03 19:39:41 -05:00
void LoadTileInfo ( ) ;
2016-01-14 22:20:50 -05:00
void LoadSprite ( uint8_t spriteY , uint8_t tileIndex , uint8_t attributes , uint8_t spriteX , bool extraSprite ) ;
2015-12-29 13:23:38 -05:00
void LoadSpriteTileInfo ( ) ;
2016-01-14 22:20:50 -05:00
void LoadExtraSprites ( ) ;
2014-06-19 19:58:15 -04:00
void ShiftTileRegisters ( ) ;
void InitializeShiftRegisters ( ) ;
void LoadNextTile ( ) ;
2014-06-18 22:54:23 -04:00
2016-06-06 23:09:22 -04:00
__forceinline uint32_t GetPixelColor ( uint32_t & paletteOffset ) ;
__forceinline virtual void DrawPixel ( ) ;
2015-08-14 21:50:14 -04:00
virtual void SendFrame ( ) ;
2014-06-18 22:54:23 -04:00
2014-06-14 11:27:55 -04:00
PPURegisters GetRegisterID ( uint16_t addr )
{
2014-06-20 21:48:55 -04:00
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 ) ;
2015-08-14 21:50:14 -04:00
virtual ~ PPU ( ) ;
2014-06-14 18:20:56 -04:00
2014-06-23 13:52:53 -04:00
void Reset ( ) ;
2016-06-05 10:26:05 -04:00
void DebugSendFrame ( ) ;
2015-07-01 23:17:14 -04:00
PPUDebugState GetState ( ) ;
2014-06-25 12:22:48 -04:00
void GetMemoryRanges ( MemoryRanges & ranges )
2014-06-15 21:45:36 -04:00
{
2015-07-29 22:10:34 -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
2015-08-05 21:43:53 -04:00
uint8_t ReadPaletteRAM ( uint16_t addr ) ;
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
2015-07-04 22:21:14 -04:00
void Exec ( ) ;
2015-07-21 18:18:20 -04:00
static void ExecStatic ( ) ;
2014-06-18 22:54:23 -04:00
2015-07-10 21:07:24 -04:00
static uint32_t GetFrameCount ( )
2014-06-18 22:54:23 -04:00
{
2015-07-10 21:07:24 -04:00
return PPU : : Instance - > _frameCount ;
2014-06-18 22:54:23 -04:00
}
2014-06-25 17:30:35 -04:00
2014-06-26 16:41:07 -04:00
static uint32_t GetFrameCycle ( )
{
return ( ( PPU : : Instance - > _scanline + 1 ) * 341 ) + PPU : : Instance - > _cycle ;
}
2015-07-29 22:10:34 -04:00
static PPUControlFlags GetControlFlags ( )
{
return PPU : : Instance - > _flags ;
}
2014-06-25 17:30:35 -04:00
static uint32_t GetCurrentCycle ( )
{
return PPU : : Instance - > _cycle ;
}
2014-06-26 16:41:07 -04:00
2016-01-24 21:35:43 -05:00
static int32_t GetCurrentScanline ( )
2014-06-26 16:41:07 -04:00
{
return PPU : : Instance - > _scanline ;
}
2015-08-05 21:43:53 -04:00
2015-08-05 20:40:10 -04:00
uint8_t * GetSpriteRam ( )
{
return _spriteRAM ;
}
uint8_t * GetSecondarySpriteRam ( )
{
return _secondarySpriteRAM ;
}
2016-02-05 23:14:27 -05:00
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 ) ;
}
2014-06-18 22:54:23 -04:00
} ;