1 #pragma once 2 3 #include "stdafx.h" 4 #include "Snapshotable.h" 5 #include "EmulationSettings.h" 6 #include "Types.h" 7 #include "DebuggerTypes.h" 8 #include "IMemoryHandler.h" 9 10 enum class NesModel; 11 12 class BaseMapper; 13 class ControlManager; 14 class Console; 15 16 enum PPURegisters 17 { 18 Control = 0x00, 19 Mask = 0x01, 20 Status = 0x02, 21 SpriteAddr = 0x03, 22 SpriteData = 0x04, 23 ScrollOffsets = 0x05, 24 VideoMemoryAddr = 0x06, 25 VideoMemoryData = 0x07, 26 SpriteDMA = 0x4014, 27 }; 28 29 class PPU : public IMemoryHandler, public Snapshotable 30 { 31 protected: 32 shared_ptr<Console> _console; 33 EmulationSettings* _settings; 34 35 PPUState _state; 36 int32_t _scanline; 37 uint32_t _cycle; 38 uint32_t _frameCount; 39 uint8_t _memoryReadBuffer; 40 41 uint8_t _paletteRAM[0x20]; 42 43 uint8_t _spriteRAM[0x100]; 44 uint8_t _secondarySpriteRAM[0x20]; 45 bool _hasSprite[257]; 46 47 uint16_t *_currentOutputBuffer; 48 uint16_t *_outputBuffers[2]; 49 50 NesModel _nesModel; 51 uint16_t _standardVblankEnd; 52 uint16_t _standardNmiScanline; 53 uint16_t _vblankEnd; 54 uint16_t _nmiScanline; 55 uint16_t _palSpriteEvalScanline; 56 57 PPUControlFlags _flags; 58 PPUStatusFlags _statusFlags; 59 60 uint16_t _intensifyColorBits; 61 uint8_t _paletteRamMask; 62 int32_t _lastUpdatedPixel; 63 64 SpriteInfo *_lastSprite; //used by HD ppu 65 66 uint16_t _ppuBusAddress; 67 TileInfo _currentTile; 68 TileInfo _nextTile; 69 TileInfo _previousTile; 70 71 SpriteInfo _spriteTiles[64]; 72 uint32_t _spriteCount; 73 uint32_t _secondaryOAMAddr; 74 bool _sprite0Visible; 75 76 uint32_t _overflowSpriteAddr; 77 uint32_t _spriteIndex; 78 79 uint8_t _openBus; 80 int32_t _openBusDecayStamp[8]; 81 uint32_t _ignoreVramRead; 82 83 uint8_t _oamCopybuffer; 84 bool _spriteInRange; 85 bool _sprite0Added; 86 uint8_t _spriteAddrH; 87 uint8_t _spriteAddrL; 88 bool _oamCopyDone; 89 uint8_t _overflowBugCounter; 90 91 bool _needStateUpdate; 92 bool _renderingEnabled; 93 bool _prevRenderingEnabled; 94 95 double _cyclesNeeded; 96 97 uint16_t _updateVramAddr; 98 uint8_t _updateVramAddrDelay; 99 100 uint32_t _minimumDrawBgCycle; 101 uint32_t _minimumDrawSpriteCycle; 102 uint32_t _minimumDrawSpriteStandardCycle; 103 104 uint64_t _oamDecayCycles[0x40]; 105 bool _enableOamDecay; 106 107 void UpdateStatusFlag(); 108 109 void SetControlRegister(uint8_t value); 110 void SetMaskRegister(uint8_t value); 111 112 bool IsRenderingEnabled(); 113 114 void SetOpenBus(uint8_t mask, uint8_t value); 115 uint8_t ApplyOpenBus(uint8_t mask, uint8_t value); 116 117 void ProcessStatusRegOpenBus(uint8_t & openBusMask, uint8_t & returnValue); 118 119 void UpdateVideoRamAddr(); 120 void IncVerticalScrolling(); 121 void IncHorizontalScrolling(); 122 uint16_t GetNameTableAddr(); 123 uint16_t GetAttributeAddr(); 124 125 __forceinline void ProcessScanline(); 126 __forceinline void ProcessSpriteEvaluation(); 127 128 void BeginVBlank(); 129 void TriggerNmi(); 130 131 void LoadTileInfo(); 132 void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite); 133 void LoadSpriteTileInfo(); 134 void LoadExtraSprites(); 135 __forceinline void ShiftTileRegisters(); 136 137 __forceinline uint8_t ReadSpriteRam(uint8_t addr); 138 __forceinline void WriteSpriteRam(uint8_t addr, uint8_t value); 139 140 void UpdateMinimumDrawCycles(); 141 142 __forceinline uint8_t GetPixelColor(); 143 __forceinline virtual void DrawPixel(); 144 void UpdateGrayscaleAndIntensifyBits(); 145 virtual void SendFrame(); 146 147 void UpdateState(); 148 149 void UpdateApuStatus(); 150 GetRegisterID(uint16_t addr)151 PPURegisters GetRegisterID(uint16_t addr) 152 { 153 if(addr == 0x4014) { 154 return PPURegisters::SpriteDMA; 155 } else { 156 return (PPURegisters)(addr & 0x07); 157 } 158 } 159 160 __forceinline void SetBusAddress(uint16_t addr); 161 __forceinline uint8_t ReadVram(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead); 162 __forceinline void WriteVram(uint16_t addr, uint8_t value); 163 164 void StreamState(bool saving) override; 165 166 public: 167 static constexpr int32_t ScreenWidth = 256; 168 static constexpr int32_t ScreenHeight = 240; 169 static constexpr int32_t PixelCount = 256*240; 170 static constexpr int32_t OutputBufferSize = 256*240*2; 171 static constexpr int32_t OamDecayCycleCount = 3000; 172 173 PPU(shared_ptr<Console> console); 174 virtual ~PPU(); 175 176 void Reset(); 177 178 void DebugSendFrame(); 179 void DebugCopyOutputBuffer(uint16_t *target); 180 void DebugUpdateFrameBuffer(bool toGrayscale); 181 void GetState(PPUDebugState &state); 182 void SetState(PPUDebugState &state); 183 GetMemoryRanges(MemoryRanges & ranges)184 void GetMemoryRanges(MemoryRanges &ranges) override 185 { 186 ranges.AddHandler(MemoryOperation::Read, 0x2000, 0x3FFF); 187 ranges.AddHandler(MemoryOperation::Write, 0x2000, 0x3FFF); 188 ranges.AddHandler(MemoryOperation::Write, 0x4014); 189 } 190 191 __forceinline uint8_t ReadPaletteRAM(uint16_t addr); 192 void WritePaletteRAM(uint16_t addr, uint8_t value); 193 194 uint8_t ReadRAM(uint16_t addr) override; 195 uint8_t PeekRAM(uint16_t addr) override; 196 void WriteRAM(uint16_t addr, uint8_t value) override; 197 198 void SetNesModel(NesModel model); 199 double GetOverclockRate(); 200 201 void Exec(); 202 void ProcessCpuClock(); 203 GetFrameCount()204 uint32_t GetFrameCount() 205 { 206 return _frameCount; 207 } 208 GetFrameCycle()209 uint32_t GetFrameCycle() 210 { 211 return ((_scanline + 1) * 341) + _cycle; 212 } 213 GetControlFlags()214 PPUControlFlags GetControlFlags() 215 { 216 return _flags; 217 } 218 GetCurrentCycle()219 uint32_t GetCurrentCycle() 220 { 221 return _cycle; 222 } 223 GetCurrentScanline()224 int32_t GetCurrentScanline() 225 { 226 return _scanline; 227 } 228 229 uint8_t* GetSpriteRam(); 230 GetSecondarySpriteRam()231 uint8_t* GetSecondarySpriteRam() 232 { 233 return _secondarySpriteRAM; 234 } 235 236 uint32_t GetPixelBrightness(uint8_t x, uint8_t y); 237 GetPixel(uint8_t x,uint8_t y)238 uint16_t GetPixel(uint8_t x, uint8_t y) 239 { 240 return _currentOutputBuffer[y << 8 | x]; 241 } 242 }; 243