NESemu/src/PPU.hpp

237 lines
3.5 KiB
C++
Raw Normal View History

2022-02-28 15:04:25 +00:00
#pragma once
2022-03-03 16:29:56 +00:00
#include <vector>
2022-02-28 15:04:25 +00:00
#include "Types.hpp"
class Bus;
2022-03-03 01:33:08 +00:00
class Screen;
2022-02-28 15:04:25 +00:00
2022-03-02 13:59:42 +00:00
enum class ScanlineType
{
PreRender,
Visible,
PostRender,
VBlank
};
enum class CycleType
{
Idle,
Fetching,
SpriteFetching,
PreFetching,
UnknownFetching
};
enum class FetchingPhase
{
NametableByte,
AttributeTableByte,
PatternTableLo,
PatternTableHi
};
union VRAMAddress
{
struct
{
2022-03-03 01:33:08 +00:00
Word CoarseX : 5;
Word CoarseY : 5;
Word NametableSel : 2;
Word FineY : 3;
2022-03-02 13:59:42 +00:00
};
Word Raw;
};
2022-03-03 16:29:56 +00:00
union ShiftRegister
{
struct
{
Byte Lo;
Byte Hi;
};
Word Raw;
};
2022-03-06 22:31:52 +00:00
struct Sprite
{
Byte Lo, Hi;
Byte Latch;
Byte Counter;
Byte FineX;
};
struct Pixel
{
Byte color;
Byte palette;
Byte priority;
bool isZeroSprite;
};
2022-02-28 16:14:32 +00:00
/**
* @brief The PPU of the NES.
*/
2022-02-28 15:04:25 +00:00
class PPU
{
friend class PPUWatcher;
2022-03-06 22:31:52 +00:00
friend class OAMViewer;
2022-02-28 15:04:25 +00:00
2022-03-03 16:29:56 +00:00
public:
static const std::vector<Color> colorTable;
2022-02-28 15:04:25 +00:00
public:
2022-03-03 01:33:08 +00:00
PPU(Bus* bus, Screen* screen);
2022-02-28 15:04:25 +00:00
2022-02-28 16:14:32 +00:00
/**
* @brief Powerup PPU.
* Internal state corresponds to powerup state
*/
2022-02-28 15:04:25 +00:00
void Powerup();
2022-02-28 16:14:32 +00:00
/**
* @brief Powerup PPU.
* Internal state corresponds to reset state
*/
2022-02-28 15:04:25 +00:00
void Reset();
2022-02-28 16:14:32 +00:00
/**
* @brief Tick PPU forward once.
*/
2022-02-28 15:04:25 +00:00
void Tick();
2022-02-28 16:14:32 +00:00
/**
* @brief Read from memory mapped PPU regs.
*/
2022-02-28 15:04:25 +00:00
Byte ReadRegister(Byte id);
2022-02-28 16:14:32 +00:00
/**
* @brief Write to memory mapped PPU regs.
*/
2022-02-28 15:04:25 +00:00
void WriteRegister(Byte id, Byte val);
2022-03-06 22:31:52 +00:00
Byte ReadOAM(Byte offset);
void WriteOAM(Byte offset, Byte val);
2022-02-28 16:14:32 +00:00
/**
* @brief Check whether the PPU finished rendering a frame.
* Returns true if the VBlankStart cycle was hit previously. The function resets
* the boolearn when it is called
*/
2022-02-28 15:04:25 +00:00
inline bool IsFrameDone() { bool returnVal = isFrameDone; isFrameDone = false; return returnVal; }
private:
2022-02-28 16:14:32 +00:00
/**
* @brief Wraps Bus::ReadPPU.
*/
2022-02-28 15:04:25 +00:00
Byte Read(Word addr);
2022-02-28 16:14:32 +00:00
/**
* @brief Wraps Bus::WritePPU.
*/
2022-02-28 15:04:25 +00:00
void Write(Word addr, Byte val);
2022-03-02 13:59:42 +00:00
void UpdateState();
2022-03-06 22:31:52 +00:00
void EvaluateBackgroundTiles();
void EvaluateSprites();
Pixel GetBackgroundPixel();
Pixel GetSpritePixel();
Color MultiplexPixel(Pixel background, Pixel sprite);
2022-03-02 13:59:42 +00:00
2022-02-28 15:04:25 +00:00
private: // Registers
union
{
struct
{
Byte BaseNametableAddr : 2;
Byte VRAMAddrIncrement : 1;
Byte SpritePatternTableAddr : 1;
Byte BackgrPatternTableAddr : 1;
Byte SpriteSize : 1;
Byte MasterSlaveSelect : 1;
Byte VBlankNMI : 1;
} Flag;
Byte Raw;
} ppuctrl;
union
{
struct
{
Byte Greyscale : 1;
Byte BackgroundOnLeft : 1;
Byte SpriteOnLeft : 1;
Byte ShowBackground : 1;
Byte ShowSprites : 1;
Byte EmphasizeRed : 1;
Byte EmphasizeGreen : 1;
Byte EmphasizeBlue : 1;
} Flag;
Byte Raw;
} ppumask;
union
{
struct
{
Byte Unused : 5;
Byte SpriteOverflow : 1;
Byte SpriteZeroHit : 1;
Byte VBlankStarted : 1;
} Flag;
Byte Raw;
} ppustatus;
struct
{
Byte x;
Byte y;
} ppuscroll;
Address ppuaddr;
2022-03-06 22:31:52 +00:00
Byte oamaddr;
2022-02-28 15:04:25 +00:00
2022-03-02 13:59:42 +00:00
VRAMAddress current{ 0 };
VRAMAddress temporary{ 0 };
uint16_t fineX;
2022-02-28 16:14:32 +00:00
bool addressLatch = false;
2022-02-28 15:04:25 +00:00
2022-03-02 13:59:42 +00:00
Byte latch = 0;
Word x, y;
Byte nametableByte = 0x00;
Byte attributeTableByte = 0x00;
Byte patternTableLo = 0x00;
Byte patternTableHi = 0x00;
2022-03-03 16:29:56 +00:00
ShiftRegister loTile{ 0 };
ShiftRegister hiTile{ 0 };
ShiftRegister hiAttribute{ 0 };
ShiftRegister loAttribute{ 0 };
2022-03-06 22:31:52 +00:00
std::vector<Byte> OAM;
std::vector<Byte> secondaryOAM;
std::vector<Sprite> sprites;
Byte OAMOverrideSignal = 0x00;
Byte freeSecondaryOAMSlot = 0x00;
Byte currentlyEvaluatedSprite = 0x00;
2022-02-28 15:04:25 +00:00
private:
2022-03-02 13:59:42 +00:00
ScanlineType scanlineType;
CycleType cycleType;
FetchingPhase fetchPhase;
uint8_t memoryAccessLatch = 0;
2022-02-28 15:04:25 +00:00
bool isFrameDone = false;
Bus* bus;
2022-03-03 01:33:08 +00:00
Screen* screen;
2022-02-28 15:04:25 +00:00
};