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"
|
2016-02-05 23:14:27 -05:00
|
|
|
#include "EmulationSettings.h"
|
2017-03-31 22:14:16 -04:00
|
|
|
#include "Types.h"
|
|
|
|
#include "DebuggerTypes.h"
|
|
|
|
#include "IMemoryHandler.h"
|
2014-06-14 10:12:10 -04:00
|
|
|
|
2015-07-21 23:05:27 -04:00
|
|
|
enum class NesModel;
|
|
|
|
|
2017-03-31 22:14:16 -04:00
|
|
|
class BaseMapper;
|
2017-11-19 23:08:23 -05:00
|
|
|
class ControlManager;
|
2018-07-01 15:21:05 -04:00
|
|
|
class Console;
|
2017-03-31 22:14:16 -04:00
|
|
|
|
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-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:
|
2018-07-01 15:21:05 -04:00
|
|
|
shared_ptr<Console> _console;
|
2018-07-13 22:19:26 -04:00
|
|
|
EmulationSettings* _settings;
|
2014-06-15 21:45:36 -04:00
|
|
|
|
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;
|
2019-11-10 17:35:29 -05:00
|
|
|
uint64_t _masterClock;
|
|
|
|
uint8_t _masterClockDivider;
|
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];
|
2017-04-02 17:41:24 -04:00
|
|
|
bool _hasSprite[257];
|
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;
|
2017-04-29 21:39:57 -04:00
|
|
|
uint16_t _standardVblankEnd;
|
|
|
|
uint16_t _standardNmiScanline;
|
2015-07-21 23:05:27 -04:00
|
|
|
uint16_t _vblankEnd;
|
2016-06-21 18:58:22 -04:00
|
|
|
uint16_t _nmiScanline;
|
2017-07-17 19:35:16 -04:00
|
|
|
uint16_t _palSpriteEvalScanline;
|
2019-11-10 17:35:29 -05: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;
|
2017-04-20 21:58:35 -04:00
|
|
|
int32_t _lastUpdatedPixel;
|
2015-07-22 22:08:28 -04:00
|
|
|
|
2015-08-14 21:50:14 -04:00
|
|
|
SpriteInfo *_lastSprite; //used by HD ppu
|
|
|
|
|
2018-06-02 22:12:00 -04:00
|
|
|
uint16_t _ppuBusAddress;
|
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];
|
2016-12-16 07:13:33 -05:00
|
|
|
uint32_t _spriteCount;
|
|
|
|
uint32_t _secondaryOAMAddr;
|
|
|
|
bool _sprite0Visible;
|
2014-07-01 18:05:54 -04:00
|
|
|
|
2016-12-16 07:13:33 -05:00
|
|
|
uint32_t _overflowSpriteAddr;
|
|
|
|
uint32_t _spriteIndex;
|
2015-12-29 13:23:38 -05:00
|
|
|
|
2016-12-16 07:13:33 -05:00
|
|
|
uint8_t _openBus;
|
2016-01-02 20:36:22 -05:00
|
|
|
int32_t _openBusDecayStamp[8];
|
2016-12-16 07:13:33 -05:00
|
|
|
uint32_t _ignoreVramRead;
|
2016-01-02 20:36:22 -05:00
|
|
|
|
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;
|
2017-03-10 21:29:48 -05:00
|
|
|
uint8_t _overflowBugCounter;
|
2016-01-11 17:18:01 -05:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
bool _needStateUpdate;
|
2016-01-11 17:18:01 -05:00
|
|
|
bool _renderingEnabled;
|
2016-02-14 13:57:47 -05:00
|
|
|
bool _prevRenderingEnabled;
|
2019-11-10 17:35:29 -05:00
|
|
|
bool _preventVblFlag;
|
2016-06-12 18:11:31 -04:00
|
|
|
|
2017-03-10 22:21:14 -05:00
|
|
|
uint16_t _updateVramAddr;
|
|
|
|
uint8_t _updateVramAddrDelay;
|
2016-10-23 13:29:37 -04:00
|
|
|
|
|
|
|
uint32_t _minimumDrawBgCycle;
|
|
|
|
uint32_t _minimumDrawSpriteCycle;
|
|
|
|
uint32_t _minimumDrawSpriteStandardCycle;
|
2017-04-08 14:13:10 -04:00
|
|
|
|
2019-05-12 12:28:01 -04:00
|
|
|
uint64_t _oamDecayCycles[0x40];
|
2017-04-08 14:13:10 -04:00
|
|
|
bool _enableOamDecay;
|
2017-11-19 23:08:23 -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();
|
|
|
|
|
2019-11-12 21:00:30 -05:00
|
|
|
void ProcessTmpAddrScrollGlitch(uint16_t normalAddr, uint16_t value, uint16_t mask);
|
|
|
|
|
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);
|
|
|
|
|
2018-12-24 23:31:32 -05:00
|
|
|
void ProcessStatusRegOpenBus(uint8_t & openBusMask, uint8_t & returnValue);
|
|
|
|
|
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();
|
|
|
|
|
2017-03-31 22:14:16 -04:00
|
|
|
__forceinline void ProcessScanline();
|
2017-04-07 19:24:34 -04:00
|
|
|
__forceinline void ProcessSpriteEvaluation();
|
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-14 18:20:56 -04:00
|
|
|
|
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();
|
2017-03-31 22:14:16 -04:00
|
|
|
__forceinline void ShiftTileRegisters();
|
2014-06-18 22:54:23 -04:00
|
|
|
|
2017-04-08 14:13:10 -04:00
|
|
|
__forceinline uint8_t ReadSpriteRam(uint8_t addr);
|
|
|
|
__forceinline void WriteSpriteRam(uint8_t addr, uint8_t value);
|
|
|
|
|
2016-10-23 13:29:37 -04:00
|
|
|
void UpdateMinimumDrawCycles();
|
|
|
|
|
2017-04-21 21:29:39 -04:00
|
|
|
__forceinline uint8_t GetPixelColor();
|
2016-06-06 23:09:22 -04:00
|
|
|
__forceinline virtual void DrawPixel();
|
2017-04-20 21:58:35 -04:00
|
|
|
void UpdateGrayscaleAndIntensifyBits();
|
2015-08-14 21:50:14 -04:00
|
|
|
virtual void SendFrame();
|
2014-06-18 22:54:23 -04:00
|
|
|
|
2017-12-04 00:09:11 -05:00
|
|
|
void UpdateState();
|
|
|
|
|
2017-04-29 21:39:57 -04:00
|
|
|
void UpdateApuStatus();
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-06-02 22:12:00 -04:00
|
|
|
__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);
|
|
|
|
|
2016-12-17 23:14:47 -05:00
|
|
|
void StreamState(bool saving) override;
|
2014-06-25 21:52:37 -04:00
|
|
|
|
2014-06-14 11:27:55 -04:00
|
|
|
public:
|
2018-07-01 15:21:05 -04:00
|
|
|
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;
|
2019-01-14 20:16:26 -05:00
|
|
|
static constexpr int32_t OamDecayCycleCount = 3000;
|
2015-07-23 23:16:31 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
PPU(shared_ptr<Console> console);
|
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();
|
2018-02-16 17:36:37 -05:00
|
|
|
void DebugCopyOutputBuffer(uint16_t *target);
|
2018-02-16 20:05:15 -05:00
|
|
|
void DebugUpdateFrameBuffer(bool toGrayscale);
|
2018-02-18 22:41:50 -05:00
|
|
|
void GetState(PPUDebugState &state);
|
|
|
|
void SetState(PPUDebugState &state);
|
2015-07-01 23:17:14 -04:00
|
|
|
|
2016-12-17 23:14:47 -05:00
|
|
|
void GetMemoryRanges(MemoryRanges &ranges) override
|
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
|
|
|
|
2017-03-31 22:14:16 -04:00
|
|
|
__forceinline uint8_t ReadPaletteRAM(uint16_t addr);
|
2016-09-05 09:05:34 -04:00
|
|
|
void WritePaletteRAM(uint16_t addr, uint8_t value);
|
2015-08-05 21:43:53 -04:00
|
|
|
|
2016-12-17 23:14:47 -05:00
|
|
|
uint8_t ReadRAM(uint16_t addr) override;
|
2018-12-24 23:31:32 -05:00
|
|
|
uint8_t PeekRAM(uint16_t addr) override;
|
2016-12-17 23:14:47 -05:00
|
|
|
void WriteRAM(uint16_t addr, uint8_t value) override;
|
2014-06-14 18:20:56 -04:00
|
|
|
|
2015-07-21 23:05:27 -04:00
|
|
|
void SetNesModel(NesModel model);
|
2019-01-13 20:18:31 -05:00
|
|
|
double GetOverclockRate();
|
2015-12-26 17:11:00 -05:00
|
|
|
|
2015-07-04 22:21:14 -04:00
|
|
|
void Exec();
|
2019-11-10 17:35:29 -05:00
|
|
|
__forceinline void Run(uint64_t runTo);
|
2014-06-18 22:54:23 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
uint32_t GetFrameCount()
|
2014-06-18 22:54:23 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _frameCount;
|
2014-06-18 22:54:23 -04:00
|
|
|
}
|
2014-06-25 17:30:35 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
uint32_t GetFrameCycle()
|
2014-06-26 16:41:07 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return ((_scanline + 1) * 341) + _cycle;
|
2014-06-26 16:41:07 -04:00
|
|
|
}
|
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
PPUControlFlags GetControlFlags()
|
2015-07-29 22:10:34 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _flags;
|
2015-07-29 22:10:34 -04:00
|
|
|
}
|
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
uint32_t GetCurrentCycle()
|
2014-06-25 17:30:35 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _cycle;
|
2014-06-25 17:30:35 -04:00
|
|
|
}
|
2014-06-26 16:41:07 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
int32_t GetCurrentScanline()
|
2014-06-26 16:41:07 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _scanline;
|
2014-06-26 16:41:07 -04:00
|
|
|
}
|
2015-08-05 21:43:53 -04:00
|
|
|
|
2018-07-06 17:54:56 -04:00
|
|
|
uint8_t* GetSpriteRam();
|
2015-08-05 20:40:10 -04:00
|
|
|
|
|
|
|
uint8_t* GetSecondarySpriteRam()
|
|
|
|
{
|
|
|
|
return _secondarySpriteRAM;
|
|
|
|
}
|
2017-09-28 20:05:00 -04:00
|
|
|
|
2018-07-13 22:19:26 -04:00
|
|
|
uint32_t GetPixelBrightness(uint8_t x, uint8_t y);
|
2017-08-30 18:31:27 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
uint16_t GetPixel(uint8_t x, uint8_t y)
|
2017-08-30 18:31:27 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _currentOutputBuffer[y << 8 | x];
|
2017-08-30 18:31:27 -04:00
|
|
|
}
|
2014-06-18 22:54:23 -04:00
|
|
|
};
|
2019-11-10 17:35:29 -05:00
|
|
|
|
|
|
|
void PPU::Run(uint64_t runTo)
|
|
|
|
{
|
|
|
|
while(_masterClock + _masterClockDivider <= runTo) {
|
|
|
|
Exec();
|
|
|
|
_masterClock += _masterClockDivider;
|
|
|
|
}
|
|
|
|
}
|