#ifndef NES_PPU_H_ #define NES_PPU_H_ #include struct nes_mapper_t; struct nes_cart_t; #define DBG_LOG(...) printf(__VA_ARGS__) #ifdef DEBUG_OAM #define OAM_LOG DBG_LOG #else #define OAM_LOG(...) #endif #ifdef DEBUG_VRAM #define VRAM_LOG DBG_LOG #else #define VRAM_LOG(...) #endif #ifdef DEBUG_PPU #define PPU_LOG DBG_LOG #else #define PPU_LOG(...) #endif #ifdef DEBUG_RENDER #define REND_LOG DBG_LOG #else #define REND_LOG(...) #endif #define nes_ppu_dots (341U) #define nes_ppu_prerender (1U) #define nes_ppu_height (240U) #define nes_ppu_postrender (1U) #define nes_ppu_vblank (20U) #define nes_ppu_active (nes_ppu_prerender + \ nes_ppu_height + \ nes_ppu_postrender) #define nes_ppu_frame (nes_ppu_active + nes_ppu_vblank) #define nes_ppu_active_cycles (nes_ppu_dots * nes_ppu_active) #define nes_ppu_vblank_cycles (nes_ppu_dots * nes_ppu_vblank) #define nes_ppu_frame_cycles (nes_ppu_dots * nes_ppu_frame) #define nes_ppu_scan_w (320U) // Effective NTSC horizontal rez #define nes_ppu_scan_h nes_ppu_height #define nes_ppu_blocks_w (32U) #define nes_ppu_blocks_h (30U) #define nes_ppu_render_w (nes_ppu_blocks_w * 8U) #define nes_ppu_render_h (nes_ppu_blocks_h * 8U) #define nes_ppu_mem_size (0x4000U) #define nes_ppu_mem_chr_start (0x0000U) #define nes_ppu_mem_chr_size (0x2000U) #define nes_ppu_mem_vram_start (0x2000U) #define nes_ppu_mem_vram_size (0x1000U) #define nes_ppu_mem_pal_start (0x3F00U) #define nes_ppu_mem_pal_size (0x0020U) #define nes_ppu_oam_size (256U) #define nes_ppu_oam_sprite_size (4U) #define nes_ppu_oam_sprite_count (nes_ppu_oam_size / \ nes_ppu_oam_sprite_size) typedef enum { ppu_Control_Nametable_Mask = 0b00000011, ppu_Control_Scroll_Page_X = 0b00000001, ppu_Control_Scroll_Page_Y = 0b00000010, ppu_Control_VRAM_Inc = 0b00000100, ppu_Control_Sprite_Bank = 0b00001000, ppu_Control_Back_Bank = 0b00010000, ppu_Control_Sprite_Size = 0b00100000, ppu_Control_Master = 0b01000000, ppu_Control_VBlank = 0b10000000, } nes_ppu_Control; typedef enum { ppu_Status_Open_Bus_Mask = 0b00011111, ppu_Status_Overflow = 0b00100000, ppu_Status_Hit = 0b01000000, ppu_Status_VBlank = 0b10000000, } nes_ppu_Status; typedef enum { ppu_Mask_Greyscale = 0b00000001, ppu_Mask_Left_Back = 0b00000010, ppu_Mask_Left_Sprite = 0b00000100, ppu_Mask_Back = 0b00001000, ppu_Mask_Sprite = 0b00010000, ppu_Mask_More_Red = 0b00100000, ppu_Mask_More_Green = 0b01000000, ppu_Mask_More_Blue = 0b10000000, } nes_ppu_Mask; typedef struct { // Memory struct nes_mapper_t* mapper; uint8_t oam[nes_ppu_oam_size]; uint8_t palette[nes_ppu_mem_pal_size]; // Timing int frame; int scanline; int cycle; int hit_line; int hit_dot; // External registers uint8_t control; uint8_t mask; uint8_t status; uint8_t scroll_x; uint8_t scroll_y; uint16_t addr; uint8_t data; uint8_t oam_addr; // Internal Registers uint8_t latch; } nes_ppu; uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr); void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val); void nes_ppu_reset(nes_ppu* ppu); int nes_ppu_init(nes_ppu* ppu, const struct nes_cart_t*); typedef enum { ppu_Result_Halt = -1, ppu_Result_Running = 0U, ppu_Result_VBlank_On, ppu_Result_VBlank_Off, ppu_Result_Ready, } nes_ppu_Result; nes_ppu_Result nes_ppu_run(nes_ppu* ppu, int cycles); #endif // NES_PPU_H_