// // Created by selim on 8/22/23. // #ifndef NES_PPU_H #define NES_PPU_H #include "Cartridge.h" #include #include #include namespace nes { struct Pixel { uint8_t R = 0; uint8_t G = 0; uint8_t B = 0; uint8_t A = 0xFF; }; class Ppu { public: static constexpr uint16_t SCREEN_WIDTH = 256; static constexpr uint16_t SCREEN_HEIGHT = 240; enum ControlAddress: uint16_t { Control = 0x0000, Mask = 0x0001, Status = 0x0002, OamAddress = 0x0003, OamData = 0x0004, Scroll = 0x0005, PpuAddress = 0x0006, PpuData = 0x0007 }; union StatusRegister { struct { uint8_t unused: 5; uint8_t spriteOverflow: 1; uint8_t spriteZeroHit: 1; uint8_t verticalBlank: 1; }; uint8_t value; }; union ControlRegister { struct { uint8_t nameTableX: 1; uint8_t nameTableY: 1; uint8_t incrementMode: 1; uint8_t patternSprite: 1; uint8_t patternBackground: 1; uint8_t spriteSize: 1; uint8_t slaveMode: 1; uint8_t enableNmi: 1; }; uint8_t value; }; union MaskRegister { struct { uint8_t grayscale: 1; uint8_t renderBackgroundLeft: 1; uint8_t renderSpritesLeft: 1; uint8_t renderBackground: 1; uint8_t renderSprites: 1; uint8_t enhanceRed: 1; uint8_t enhanceGreen: 1; uint8_t enhanceBlue: 1; }; uint8_t value; }; union LoopyRegister { struct { uint8_t coarseX : 5; uint8_t coarseY : 5; uint8_t nameTableX : 1; uint8_t nameTableY : 1; uint8_t fineY : 3; uint8_t unused : 1; }; uint16_t value; }; public: Ppu(); bool tick(); void write(uint16_t address, uint8_t value); uint8_t read(uint16_t address); void setPixel(uint16_t row, uint16_t column, Pixel pixel); void connect(std::shared_ptr cartridge); public: std::function onNewFrame; private: uint8_t internalRead(uint16_t address); void internalWrite(uint16_t address, uint8_t value); Pixel getColor(uint8_t palette, uint8_t pixel); private: int16_t _column; int16_t _scanline; StatusRegister _status; ControlRegister _control; MaskRegister _mask; LoopyRegister _vRamAddress; LoopyRegister _tRamAddress; bool _addressWriteInProgress; uint8_t _dataTemp; uint8_t _fineX; private: std::unique_ptr _nameTable; std::unique_ptr _palette; std::unique_ptr _paletteTable; private: std::unique_ptr _frameBuffer; std::shared_ptr _cartridge; }; } #endif //NES_PPU_H